Merge branch 'akpm' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Nov 2015 22:32:45 +0000 (14:32 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Nov 2015 22:32:45 +0000 (14:32 -0800)
Merge second patch-bomb from Andrew Morton:

 - most of the rest of MM

 - procfs

 - lib/ updates

 - printk updates

 - bitops infrastructure tweaks

 - checkpatch updates

 - nilfs2 update

 - signals

 - various other misc bits: coredump, seqfile, kexec, pidns, zlib, ipc,
   dma-debug, dma-mapping, ...

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (102 commits)
  ipc,msg: drop dst nil validation in copy_msg
  include/linux/zutil.h: fix usage example of zlib_adler32()
  panic: release stale console lock to always get the logbuf printed out
  dma-debug: check nents in dma_sync_sg*
  dma-mapping: tidy up dma_parms default handling
  pidns: fix set/getpriority and ioprio_set/get in PRIO_USER mode
  kexec: use file name as the output message prefix
  fs, seqfile: always allow oom killer
  seq_file: reuse string_escape_str()
  fs/seq_file: use seq_* helpers in seq_hex_dump()
  coredump: change zap_threads() and zap_process() to use for_each_thread()
  coredump: ensure all coredumping tasks have SIGNAL_GROUP_COREDUMP
  signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT)
  signal: introduce kernel_signal_stop() to fix jffs2_garbage_collect_thread()
  signal: turn dequeue_signal_lock() into kernel_dequeue_signal()
  signals: kill block_all_signals() and unblock_all_signals()
  nilfs2: fix gcc uninitialized-variable warnings in powerpc build
  nilfs2: fix gcc unused-but-set-variable warnings
  MAINTAINERS: nilfs2: add header file for tracing
  nilfs2: add tracepoints for analyzing reading and writing metadata files
  ...

1255 files changed:
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-arvo [new file with mode: 0644]
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-isku [new file with mode: 0644]
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-koneplus
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-konepure [new file with mode: 0644]
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-kovaplus
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-lua [new file with mode: 0644]
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-pyra
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-ryos [new file with mode: 0644]
Documentation/ABI/obsolete/sysfs-driver-hid-roccat-savu [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-hid-corsair [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-isku [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-lua [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-ryos [deleted file]
Documentation/ABI/testing/sysfs-driver-hid-roccat-savu [deleted file]
Documentation/DocBook/alsa-driver-api.tmpl
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/devicetree/bindings/arc/archs-idu-intc.txt [deleted file]
Documentation/devicetree/bindings/arc/archs-intc.txt [deleted file]
Documentation/devicetree/bindings/arc/interrupts.txt [deleted file]
Documentation/devicetree/bindings/arm/calxeda/combophy.txt [deleted file]
Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt [deleted file]
Documentation/devicetree/bindings/arm/davinci/cp-intc.txt [deleted file]
Documentation/devicetree/bindings/arm/gic-v3.txt [deleted file]
Documentation/devicetree/bindings/arm/gic.txt [deleted file]
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
Documentation/devicetree/bindings/arm/lpc32xx-mic.txt [deleted file]
Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt [deleted file]
Documentation/devicetree/bindings/arm/mrvl/intc.txt [deleted file]
Documentation/devicetree/bindings/arm/omap/intc.txt [deleted file]
Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt [deleted file]
Documentation/devicetree/bindings/arm/spear/shirq.txt [deleted file]
Documentation/devicetree/bindings/arm/tegra/nvidia,nvec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt [deleted file]
Documentation/devicetree/bindings/arm/vic.txt [deleted file]
Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt [deleted file]
Documentation/devicetree/bindings/c6x/interrupt.txt [deleted file]
Documentation/devicetree/bindings/cris/interrupts.txt [deleted file]
Documentation/devicetree/bindings/crypto/fsl-sec4.txt
Documentation/devicetree/bindings/display/arm,pl11x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/armada/marvell,dove-lcd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/atmel,lcdc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/adi,adv7123.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/ps8622.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/ptn3460.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/tda998x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/cirrus,clps711x-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/connector/dvi-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/connector/hdmi-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/connector/vga-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos-mic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos7-decon.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_dp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_hdmiddc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_hdmiphy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/exynos_mixer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/fsl,dcu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/imx/fsl,imx-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/imx/hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/imx/ldb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/marvell,pxa2xx-lcdc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/mipi-dsi-bus.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/dsi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/edp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/gpu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/msm/mdp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/mxsfb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/display-timing.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lg,ld070wx3-sl01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lg,lg4573.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lg,lh500wx1-sd03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/lgphilips,lb035q02.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/panel-dpi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/panel-dsi-cm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/samsung,ld9040.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/sharp,ls037v7dw01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/simple-panel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/sony,acx565akm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/tpo,td043mtea1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/renesas,du.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/simple-framebuffer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/sm501fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ssd1289fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ssd1307fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/st,stih4xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/tegra/nvidia,tegra114-mipi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,dra7-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,omap2-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,omap3-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,omap4-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,opa362.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,tfp410.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,tpd12s015.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/tilcdc/panel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/tilcdc/tfp410.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/via,vt8500-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/wm,prizm-ge-rops.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/wm,wm8505-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt [deleted file]
Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt [deleted file]
Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt [deleted file]
Documentation/devicetree/bindings/drm/i2c/tda998x.txt [deleted file]
Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt [deleted file]
Documentation/devicetree/bindings/drm/imx/hdmi.txt [deleted file]
Documentation/devicetree/bindings/drm/imx/ldb.txt [deleted file]
Documentation/devicetree/bindings/drm/msm/dsi.txt [deleted file]
Documentation/devicetree/bindings/drm/msm/edp.txt [deleted file]
Documentation/devicetree/bindings/drm/msm/gpu.txt [deleted file]
Documentation/devicetree/bindings/drm/msm/hdmi.txt [deleted file]
Documentation/devicetree/bindings/drm/msm/mdp.txt [deleted file]
Documentation/devicetree/bindings/drm/tilcdc/panel.txt [deleted file]
Documentation/devicetree/bindings/drm/tilcdc/tfp410.txt [deleted file]
Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt [deleted file]
Documentation/devicetree/bindings/eeprom.txt [deleted file]
Documentation/devicetree/bindings/eeprom/at25.txt [new file with mode: 0644]
Documentation/devicetree/bindings/eeprom/eeprom.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fb/mxsfb.txt [deleted file]
Documentation/devicetree/bindings/fb/sm501fb.txt [deleted file]
Documentation/devicetree/bindings/fpga/altera-socfpga-fpga-mgr.txt
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt [deleted file]
Documentation/devicetree/bindings/gpu/st,stih4xx.txt [deleted file]
Documentation/devicetree/bindings/hid/hid-over-i2c.txt [deleted file]
Documentation/devicetree/bindings/hwmon/ina209.txt [deleted file]
Documentation/devicetree/bindings/hwmon/ina2xx.txt
Documentation/devicetree/bindings/hwrng/atmel-trng.txt [deleted file]
Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt [deleted file]
Documentation/devicetree/bindings/hwrng/omap_rng.txt [deleted file]
Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt [deleted file]
Documentation/devicetree/bindings/iio/accel/lis302.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/dac/ti,dac7512.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/pressure/bmp085.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/ads7846.txt
Documentation/devicetree/bindings/input/da9062-onkey.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/gpio-keys-polled.txt
Documentation/devicetree/bindings/input/gpio-keys.txt
Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
Documentation/devicetree/bindings/input/hid-over-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
Documentation/devicetree/bindings/input/rotary-encoder.txt
Documentation/devicetree/bindings/input/samsung-keypad.txt
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/axis,crisv32-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/img,meta-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/img,pdc-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/nxp,lpc3220-mic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/open-pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/samsung,exynos4210-combiner.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/snps,arc700-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/snps,archs-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/st,spear3xx-shirq.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/ti,c64x+megamod-pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/ti,cp-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/ti,omap2-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/via,vt8500-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/88pm860x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/gpio-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/lp855x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/max8925-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/sky81452-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/backlight/tps65217-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
Documentation/devicetree/bindings/mailbox/sti-mailbox.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/calxeda-ddr-ctrlr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/metag/meta-intc.txt [deleted file]
Documentation/devicetree/bindings/metag/pdc-intc.txt [deleted file]
Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
Documentation/devicetree/bindings/mfd/sky81452.txt
Documentation/devicetree/bindings/mfd/tc3589x.txt
Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt [deleted file]
Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt [deleted file]
Documentation/devicetree/bindings/misc/at25.txt [deleted file]
Documentation/devicetree/bindings/misc/bmp085.txt [deleted file]
Documentation/devicetree/bindings/misc/lis302.txt [deleted file]
Documentation/devicetree/bindings/misc/ti,dac7512.txt [deleted file]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/mtd/partition.txt
Documentation/devicetree/bindings/mtd/vf610-nfc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/nvec/nvidia,nvec.txt [deleted file]
Documentation/devicetree/bindings/open-pic.txt [deleted file]
Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b080uan01.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b101aw03.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b101ean01.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b101xtn01.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b116xw03.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b133htn01.txt [deleted file]
Documentation/devicetree/bindings/panel/auo,b133xtn01.txt [deleted file]
Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt [deleted file]
Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt [deleted file]
Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt [deleted file]
Documentation/devicetree/bindings/panel/edt,et057090dhu.txt [deleted file]
Documentation/devicetree/bindings/panel/edt,et070080dh6.txt [deleted file]
Documentation/devicetree/bindings/panel/edt,etm0700g0dh6.txt [deleted file]
Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt [deleted file]
Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt [deleted file]
Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt [deleted file]
Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt [deleted file]
Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt [deleted file]
Documentation/devicetree/bindings/panel/innolux,at043tn24.txt [deleted file]
Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt [deleted file]
Documentation/devicetree/bindings/panel/innolux,n116bge.txt [deleted file]
Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt [deleted file]
Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt [deleted file]
Documentation/devicetree/bindings/panel/lg,lb070wv8.txt [deleted file]
Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt [deleted file]
Documentation/devicetree/bindings/panel/lg,lg4573.txt [deleted file]
Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt [deleted file]
Documentation/devicetree/bindings/panel/lg,lp129qe.txt [deleted file]
Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt [deleted file]
Documentation/devicetree/bindings/panel/okaya,rs800480t-7x0gp.txt [deleted file]
Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt [deleted file]
Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt [deleted file]
Documentation/devicetree/bindings/panel/samsung,ld9040.txt [deleted file]
Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt [deleted file]
Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt [deleted file]
Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt [deleted file]
Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt [deleted file]
Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt [deleted file]
Documentation/devicetree/bindings/panel/simple-panel.txt [deleted file]
Documentation/devicetree/bindings/pci/altera-pcie-msi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/altera-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/hisilicon-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/host-generic-pci.txt
Documentation/devicetree/bindings/pci/layerscape-pci.txt
Documentation/devicetree/bindings/pci/pci.txt
Documentation/devicetree/bindings/phy/calxeda-combophy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/keystone-usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/mxs-usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/nvidia,tegra20-usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,usb-8x16-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/wakeup-source.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rng/atmel-trng.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rng/brcm,iproc-rng200.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rng/omap_rng.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rng/timeriomem_rng.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/isil,isl12057.txt
Documentation/devicetree/bindings/rtc/rtc-opal.txt
Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
Documentation/devicetree/bindings/sound/ak4613.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ak4642.txt
Documentation/devicetree/bindings/sound/atmel-classd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7213.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da7219.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
Documentation/devicetree/bindings/sound/nau8825.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/rockchip-i2s.txt
Documentation/devicetree/bindings/sound/rockchip-spdif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt
Documentation/devicetree/bindings/sound/sun4i-codec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tdm-slot.txt
Documentation/devicetree/bindings/usb/keystone-phy.txt [deleted file]
Documentation/devicetree/bindings/usb/mxs-phy.txt [deleted file]
Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt [deleted file]
Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt [deleted file]
Documentation/devicetree/bindings/usb/samsung-usbphy.txt [deleted file]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/video/adi,adv7123.txt [deleted file]
Documentation/devicetree/bindings/video/adi,adv7511.txt [deleted file]
Documentation/devicetree/bindings/video/analog-tv-connector.txt [deleted file]
Documentation/devicetree/bindings/video/arm,pl11x.txt [deleted file]
Documentation/devicetree/bindings/video/atmel,lcdc.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/88pm860x.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/lp855x.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt [deleted file]
Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt [deleted file]
Documentation/devicetree/bindings/video/bridge/ps8622.txt [deleted file]
Documentation/devicetree/bindings/video/bridge/ptn3460.txt [deleted file]
Documentation/devicetree/bindings/video/cirrus,clps711x-fb.txt [deleted file]
Documentation/devicetree/bindings/video/display-timing.txt [deleted file]
Documentation/devicetree/bindings/video/dvi-connector.txt [deleted file]
Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt [deleted file]
Documentation/devicetree/bindings/video/exynos-mic.txt [deleted file]
Documentation/devicetree/bindings/video/exynos5433-decon.txt [deleted file]
Documentation/devicetree/bindings/video/exynos7-decon.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_dp.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_dsim.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_hdmi.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_hdmiddc.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_hdmiphy.txt [deleted file]
Documentation/devicetree/bindings/video/exynos_mixer.txt [deleted file]
Documentation/devicetree/bindings/video/fsl,dcu.txt [deleted file]
Documentation/devicetree/bindings/video/fsl,imx-fb.txt [deleted file]
Documentation/devicetree/bindings/video/hdmi-connector.txt [deleted file]
Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt [deleted file]
Documentation/devicetree/bindings/video/panel-dpi.txt [deleted file]
Documentation/devicetree/bindings/video/panel-dsi-cm.txt [deleted file]
Documentation/devicetree/bindings/video/renesas,du.txt [deleted file]
Documentation/devicetree/bindings/video/rockchip-drm.txt [deleted file]
Documentation/devicetree/bindings/video/rockchip-vop.txt [deleted file]
Documentation/devicetree/bindings/video/samsung-fimd.txt [deleted file]
Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt [deleted file]
Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt [deleted file]
Documentation/devicetree/bindings/video/simple-framebuffer.txt [deleted file]
Documentation/devicetree/bindings/video/sony,acx565akm.txt [deleted file]
Documentation/devicetree/bindings/video/ssd1289fb.txt [deleted file]
Documentation/devicetree/bindings/video/ssd1307fb.txt [deleted file]
Documentation/devicetree/bindings/video/thine,thc63lvdm83d [deleted file]
Documentation/devicetree/bindings/video/ti,dra7-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,omap-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,omap2-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,omap3-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,omap4-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,omap5-dss.txt [deleted file]
Documentation/devicetree/bindings/video/ti,opa362.txt [deleted file]
Documentation/devicetree/bindings/video/ti,tfp410.txt [deleted file]
Documentation/devicetree/bindings/video/ti,tpd12s015.txt [deleted file]
Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt [deleted file]
Documentation/devicetree/bindings/video/tpo,td043mtea1.txt [deleted file]
Documentation/devicetree/bindings/video/vga-connector.txt [deleted file]
Documentation/devicetree/bindings/video/via,vt8500-fb.txt [deleted file]
Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt [deleted file]
Documentation/devicetree/bindings/video/wm,wm8505-fb.txt [deleted file]
Documentation/devicetree/bindings/x86/interrupt.txt [deleted file]
Documentation/input/rotary-encoder.txt
Documentation/input/userio.txt [new file with mode: 0644]
Documentation/sound/alsa/hda_codec.txt [deleted file]
Documentation/trace/events.txt
Documentation/trace/ftrace.txt
MAINTAINERS
arch/arc/Makefile
arch/arc/boot/dts/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am437x-sk-evm.dts
arch/arm/boot/dts/imx28-tx28.dts
arch/arm/boot/dts/imx53-tx53-x03x.dts
arch/arm/boot/dts/imx6qdl-tx6.dtsi
arch/arm/boot/dts/twl4030.dtsi
arch/arm/include/asm/Kbuild
arch/arm/include/asm/mach/pci.h
arch/arm/kernel/bios32.c
arch/arm64/boot/dts/Makefile
arch/arm64/boot/dts/amd/amd-overdrive.dts
arch/h8300/boot/dts/Makefile
arch/metag/Makefile
arch/metag/boot/dts/Makefile
arch/mips/boot/dts/Makefile
arch/powerpc/platforms/pseries/setup.c
arch/sh/boards/mach-rsk/setup.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/pci_common.c
arch/sparc/kernel/pci_impl.h
arch/x86/kernel/ftrace.c
arch/x86/kernel/livepatch.c
arch/x86/pci/common.c
arch/x86/pci/legacy.c
arch/xtensa/Makefile
arch/xtensa/boot/dts/Makefile
drivers/acpi/nfit.c
drivers/acpi/osl.c
drivers/base/class.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/pktcdvd.c
drivers/crypto/hifn_795x.c
drivers/edac/i3200_edac.c
drivers/edac/ie31200_edac.c
drivers/edac/x38_edac.c
drivers/gpio/gpio-mxc.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_audio.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-appleir.c
drivers/hid/hid-aureal.c
drivers/hid/hid-core.c
drivers/hid/hid-corsair.c [new file with mode: 0644]
drivers/hid/hid-dr.c
drivers/hid/hid-elecom.c
drivers/hid/hid-elo.c
drivers/hid/hid-gfrm.c [new file with mode: 0644]
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lenovo.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-microsoft.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-rmi.c
drivers/hid/hid-saitek.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hid-uclogic.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h
drivers/hwmon/applesmc.c
drivers/i2c/busses/i2c-ismt.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/agent.c
drivers/infiniband/core/cache.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/mad_priv.h
drivers/infiniband/core/multicast.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/uverbs_marshall.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/cxgb3/iwch_cq.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb3/iwch_provider.h
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/mlx4/ah.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/mr.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/nes/nes_hw.h
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/nes/nes_verbs.h
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_stats.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
drivers/infiniband/hw/qib/qib_keys.c
drivers/infiniband/hw/qib/qib_mr.c
drivers/infiniband/hw/qib/qib_qp.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/hw/qib/qib_ruc.c
drivers/infiniband/hw/qib/qib_uc.c
drivers/infiniband/hw/qib/qib_ud.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/hw/qib/qib_verbs.h
drivers/infiniband/hw/usnic/usnic_ib_main.c
drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_memory.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/evdev.c
drivers/input/ff-core.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/turbografx.c
drivers/input/joystick/walkera0701.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/snvs_pwrkey.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/Kconfig
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/ad714x.c
drivers/input/misc/ad714x.h
drivers/input/misc/da9063_onkey.c
drivers/input/misc/hp_sdc_rtc.c
drivers/input/misc/kxtj9.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/xen-kbdfront.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/parkbd.c
drivers/input/serio/userio.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/cyttsp4_i2c.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/ft6236.c [new file with mode: 0644]
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/rohm_bu21023.c [new file with mode: 0644]
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/zforce_ts.c
drivers/mailbox/Kconfig
drivers/mailbox/Makefile
drivers/mailbox/mailbox-sti.c [new file with mode: 0644]
drivers/mailbox/mailbox-test.c [new file with mode: 0644]
drivers/mailbox/omap-mailbox.c
drivers/mailbox/pcc.c
drivers/md/bcache/closure.c
drivers/mfd/intel-lpss.c
drivers/misc/c2port/core.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/lpddr/lpddr2_nvm.c
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/lantiq-flash.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bcm47xxnflash/main.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/brcmnand/bcm63138_nand.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/brcmnand/brcmnand.h
drivers/mtd/nand/brcmnand/iproc_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsl_upm.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/hisi504_nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/r852.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/txx9ndfmc.c
drivers/mtd/nand/vf610_nfc.c [new file with mode: 0644]
drivers/mtd/ofpart.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/samsung.c
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/nxp-spifi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/tests/speedtest.c
drivers/mtd/tests/torturetest.c
drivers/mtd/ubi/gluebi.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
drivers/net/ethernet/chelsio/cxgb4/t4_chip_type.h [new file with mode: 0644]
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/intel/i40e/i40e_osdep.h
drivers/net/ethernet/intel/i40evf/i40e_osdep.h
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_resources.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/ti/netcp_core.c
drivers/nvme/host/pci.c
drivers/of/Kconfig
drivers/of/address.c
drivers/of/base.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/of_pci.c
drivers/of/of_reserved_mem.c
drivers/of/overlay.c
drivers/of/platform.c
drivers/of/unittest.c
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pci-exynos.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-keystone-dw.c
drivers/pci/host/pci-keystone.h
drivers/pci/host/pci-layerscape.c
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-altera-msi.c [new file with mode: 0644]
drivers/pci/host/pcie-altera.c [new file with mode: 0644]
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-designware.h
drivers/pci/host/pcie-hisi.c [new file with mode: 0644]
drivers/pci/host/pcie-iproc-platform.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-iproc.h
drivers/pci/host/pcie-rcar.c
drivers/pci/host/pcie-spear13xx.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/iov.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/platform/x86/ibm_rtl.c
drivers/platform/x86/intel_ips.c
drivers/scsi/Kconfig
drivers/scsi/qla4xxx/ql4_nx.c
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
drivers/staging/mt29f_spinand/mt29f_spinand.c
drivers/staging/rdma/amso1100/c2_qp.c
drivers/staging/rdma/ehca/ehca_reqs.c
drivers/staging/rdma/hfi1/keys.c
drivers/staging/rdma/hfi1/mr.c
drivers/staging/rdma/hfi1/qp.c
drivers/staging/rdma/hfi1/rc.c
drivers/staging/rdma/hfi1/ruc.c
drivers/staging/rdma/hfi1/uc.c
drivers/staging/rdma/hfi1/ud.c
drivers/staging/rdma/hfi1/verbs.c
drivers/staging/rdma/hfi1/verbs.h
drivers/staging/rdma/ipath/ipath_rc.c
drivers/staging/rdma/ipath/ipath_ruc.c
drivers/staging/rdma/ipath/ipath_uc.c
drivers/staging/rdma/ipath/ipath_ud.c
drivers/staging/rdma/ipath/ipath_verbs.c
drivers/staging/rdma/ipath/ipath_verbs.h
drivers/tty/n_tracerouter.c
drivers/tty/n_tracesink.c
drivers/usb/host/xhci.h
fs/Makefile
fs/btrfs/backref.c
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
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/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h
fs/btrfs/inode-item.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/locking.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/props.c
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/raid56.c
fs/btrfs/reada.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/sysfs.h
fs/btrfs/tests/free-space-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cifs/readdir.c
fs/ecryptfs/inode.c
fs/ext4/Makefile
fs/ext4/balloc.c
fs/ext4/block_validity.c
fs/ext4/crypto.c
fs/ext4/crypto_fname.c
fs/ext4/crypto_key.c
fs/ext4/crypto_policy.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/extents_status.c
fs/ext4/extents_status.h
fs/ext4/ialloc.c
fs/ext4/indirect.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/mmp.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/readpage.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/ext4/sysfs.c [new file with mode: 0644]
fs/ext4/xattr.c
fs/jbd2/checkpoint.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/jffs2/dir.c
fs/jffs2/malloc.c
fs/jffs2/readinode.c
fs/jffs2/wbuf.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/objlayout/objio_osd.c
fs/proc/proc_sysctl.c
fs/tracefs/inode.c
include/asm-generic/bitops/count_zeros.h [deleted file]
include/asm-generic/cmpxchg.h
include/asm-generic/io-64-nonatomic-hi-lo.h
include/asm-generic/io-64-nonatomic-lo-hi.h
include/drm/i915_component.h
include/dt-bindings/input/input.h
include/dt-bindings/input/linux-event-codes.h [new symlink]
include/linux/aer.h
include/linux/blkpg.h [new file with mode: 0644]
include/linux/count_zeros.h [new file with mode: 0644]
include/linux/ftrace.h
include/linux/hid.h
include/linux/input.h
include/linux/input/edt-ft5x06.h [deleted file]
include/linux/io-64-nonatomic-hi-lo.h [new file with mode: 0644]
include/linux/io-64-nonatomic-lo-hi.h [new file with mode: 0644]
include/linux/jbd2.h
include/linux/miscdevice.h
include/linux/mlx4/device.h
include/linux/mlx4/qp.h
include/linux/mod_devicetable.h
include/linux/msi.h
include/linux/mtd/nand.h
include/linux/mtd/spi-nor.h
include/linux/of_irq.h
include/linux/of_pci.h
include/linux/pci.h
include/linux/platform_data/mtd-nand-pxa3xx.h
include/linux/ring_buffer.h
include/linux/rotary_encoder.h
include/linux/sunrpc/svc_rdma.h
include/linux/trace_events.h
include/linux/tracepoint.h
include/rdma/ib_addr.h
include/rdma/ib_cache.h
include/rdma/ib_pack.h
include/rdma/ib_sa.h
include/rdma/ib_verbs.h
include/rdma/rdma_cm.h
include/sound/da7213.h
include/sound/da7219-aad.h [new file with mode: 0644]
include/sound/da7219.h [new file with mode: 0644]
include/sound/designware_i2s.h
include/sound/hda_regmap.h
include/sound/hdaudio.h
include/sound/hdaudio_ext.h
include/sound/pcm.h
include/sound/pxa2xx-lib.h
include/sound/rcar_snd.h [deleted file]
include/sound/rt5640.h
include/sound/rt5645.h
include/sound/simple_card.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/trace/define_trace.h
include/trace/events/btrfs.h
include/trace/events/gpio.h
include/trace/perf.h
include/trace/trace_events.h
include/uapi/linux/Kbuild
include/uapi/linux/blkpg.h
include/uapi/linux/btrfs.h
include/uapi/linux/fs.h
include/uapi/linux/input-event-codes.h [new file with mode: 0644]
include/uapi/linux/input.h
include/uapi/linux/pci_regs.h
include/uapi/linux/userio.h [new file with mode: 0644]
include/uapi/mtd/mtd-user.h
include/uapi/rdma/ib_user_verbs.h
include/uapi/sound/asoc.h
include/uapi/sound/asound.h
include/uapi/sound/emu10k1.h
include/uapi/sound/firewire.h
include/uapi/sound/hdspm.h
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/ring_buffer_benchmark.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_benchmark.c
kernel/trace/trace_branch.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_export.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_kdb.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_output.c
kernel/trace/trace_output.h
kernel/trace/trace_printk.c
kernel/trace/trace_probe.h
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_stack.c
kernel/trace/trace_syscalls.c
kernel/tracepoint.c
lib/mpi/longlong.h
lib/mpi/mpicoder.c
mm/huge_memory.c
net/9p/trans_rdma.c
net/openvswitch/datapath.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_send.c
net/rds/iw.c
net/rds/iw.h
net/rds/iw_cm.c
net/rds/iw_rdma.c
net/rds/iw_send.c
net/rds/rdma_transport.c
net/sctp/socket.c
net/socket.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h
samples/trace_events/trace-events-sample.h
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
scripts/recordmcount.c
scripts/recordmcount.h
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm-lib.c
sound/arm/pxa2xx-pcm.c
sound/arm/pxa2xx-pcm.h
sound/core/Kconfig
sound/core/Makefile
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_writeq.c
sound/firewire/Kconfig
sound/firewire/Makefile
sound/firewire/amdtp-am824.c [new file with mode: 0644]
sound/firewire/amdtp-am824.h [new file with mode: 0644]
sound/firewire/amdtp-stream.c [new file with mode: 0644]
sound/firewire/amdtp-stream.h [new file with mode: 0644]
sound/firewire/amdtp.c [deleted file]
sound/firewire/amdtp.h [deleted file]
sound/firewire/bebob/Makefile
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob.h
sound/firewire/bebob/bebob_focusrite.c
sound/firewire/bebob/bebob_maudio.c
sound/firewire/bebob/bebob_midi.c
sound/firewire/bebob/bebob_pcm.c
sound/firewire/bebob/bebob_proc.c
sound/firewire/bebob/bebob_stream.c
sound/firewire/bebob/bebob_terratec.c
sound/firewire/bebob/bebob_yamaha.c
sound/firewire/dice/Makefile
sound/firewire/dice/dice-midi.c
sound/firewire/dice/dice-pcm.c
sound/firewire/dice/dice-stream.c
sound/firewire/dice/dice.c
sound/firewire/dice/dice.h
sound/firewire/digi00x/Makefile [new file with mode: 0644]
sound/firewire/digi00x/amdtp-dot.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-hwdep.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-midi.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-pcm.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-proc.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-stream.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x-transaction.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x.c [new file with mode: 0644]
sound/firewire/digi00x/digi00x.h [new file with mode: 0644]
sound/firewire/fcp.c
sound/firewire/fireworks/Makefile
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_command.c
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/fireworks/fireworks_pcm.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/lib.c
sound/firewire/lib.h
sound/firewire/oxfw/Makefile
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw-pcm.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/oxfw/oxfw.c
sound/firewire/oxfw/oxfw.h
sound/firewire/tascam/Makefile [new file with mode: 0644]
sound/firewire/tascam/amdtp-tascam.c [new file with mode: 0644]
sound/firewire/tascam/tascam-hwdep.c [new file with mode: 0644]
sound/firewire/tascam/tascam-midi.c [new file with mode: 0644]
sound/firewire/tascam/tascam-pcm.c [new file with mode: 0644]
sound/firewire/tascam/tascam-proc.c [new file with mode: 0644]
sound/firewire/tascam/tascam-stream.c [new file with mode: 0644]
sound/firewire/tascam/tascam-transaction.c [new file with mode: 0644]
sound/firewire/tascam/tascam.c [new file with mode: 0644]
sound/firewire/tascam/tascam.h [new file with mode: 0644]
sound/hda/ext/hdac_ext_stream.c
sound/hda/hda_bus_type.c
sound/hda/hdac_bus.c
sound/hda/hdac_device.c
sound/hda/hdac_i915.c
sound/hda/hdac_regmap.c
sound/hda/hdac_stream.c
sound/hda/hdac_sysfs.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_sysfs.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/korg1212/korg1212.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-classd.c [new file with mode: 0644]
sound/soc/atmel/atmel-classd.h [new file with mode: 0644]
sound/soc/atmel/atmel_wm8904.c
sound/soc/au1x/db1000.c
sound/soc/au1x/db1200.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bfin-eval-adau1373.c
sound/soc/blackfin/bfin-eval-adau1701.c
sound/soc/blackfin/bfin-eval-adav80x.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad193x-i2c.c
sound/soc/codecs/ad193x-spi.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4613.c [new file with mode: 0644]
sound/soc/codecs/ak4642.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/da7213.c
sound/soc/codecs/da7213.h
sound/soc/codecs/da7219-aad.c [new file with mode: 0644]
sound/soc/codecs/da7219-aad.h [new file with mode: 0644]
sound/soc/codecs/da7219.c [new file with mode: 0644]
sound/soc/codecs/da7219.h [new file with mode: 0644]
sound/soc/codecs/es8328.c
sound/soc/codecs/hdmi.c [deleted file]
sound/soc/codecs/nau8825.c [new file with mode: 0644]
sound/soc/codecs/nau8825.h [new file with mode: 0644]
sound/soc/codecs/rl6347a.c
sound/soc/codecs/rl6347a.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/ssm2518.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8998.c [new file with mode: 0644]
sound/soc/codecs/wm8998.h [new file with mode: 0644]
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-spdif.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/skl_rt286.c [new file with mode: 0644]
sound/soc/intel/common/Makefile
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.h
sound/soc/intel/common/sst-firmware.c
sound/soc/intel/skylake/Makefile
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-topology.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/armada-370-db.c
sound/soc/mediatek/mt8173-max98090.c
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/omap/n810.c
sound/soc/omap/rx51.c
sound/soc/pxa/brownstone.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/imote2.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/ttc-dkb.c
sound/soc/qcom/lpass-cpu.c
sound/soc/rockchip/Kconfig
sound/soc/rockchip/Makefile
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_i2s.h
sound/soc/rockchip/rockchip_spdif.c [new file with mode: 0644]
sound/soc/rockchip/rockchip_spdif.h [new file with mode: 0644]
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/sh/Kconfig
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rcar_snd.h [new file with mode: 0644]
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/siu_dai.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sunxi/Kconfig [new file with mode: 0644]
sound/soc/sunxi/Makefile [new file with mode: 0644]
sound/soc/sunxi/sun4i-codec.c [new file with mode: 0644]
sound/soc/ux500/mop500.c
sound/soc/ux500/ux500_msp_dai.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/midi.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/stream.c
sound/usb/usbaudio.h

diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-arvo b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-arvo
new file mode 100644 (file)
index 0000000..55e281b
--- /dev/null
@@ -0,0 +1,53 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/actual_profile
+Date:          Januar 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The integer value of this attribute ranges from 1-5.
+               When read, this attribute returns the number of the actual
+               profile which is also the profile that's active on device startup.
+               When written this attribute activates the selected profile
+               immediately.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/button
+Date:          Januar 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The keyboard can store short macros with consist of 1 button with
+               several modifier keys internally.
+               When written, this file lets one set the sequence for a specific
+               button for a specific profile. Button and profile numbers are
+               included in written data. The data has to be 24 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/info
+Date:          Januar 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns some info about the device like the
+               installed firmware version.
+               The size of the data is 8 bytes in size.
+               This file is readonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/key_mask
+Date:          Januar 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The keyboard lets the user deactivate 5 certain keys like the
+               windows and application keys, to protect the user from the outcome
+               of accidentally pressing them.
+               The integer value of this attribute has bits 0-4 set depending
+               on the state of the corresponding key.
+               When read, this file returns the current state of the buttons.
+               When written, the given buttons are activated/deactivated
+               immediately.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/mode_key
+Date:          Januar 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The keyboard has a condensed layout without num-lock key.
+               Instead it uses a mode-key which activates a gaming mode where
+               the assignment of the number block changes.
+               The integer value of this attribute ranges from 0 (OFF) to 1 (ON).
+               When read, this file returns the actual state of the key.
+               When written, the key is activated/deactivated immediately.
+Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-isku b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-isku
new file mode 100644 (file)
index 0000000..c601d0f
--- /dev/null
@@ -0,0 +1,153 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/actual_profile
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The integer value of this attribute ranges from 0-4.
+               When read, this attribute returns the number of the actual
+               profile. This value is persistent, so its equivalent to the
+               profile that's active when the device is powered on next time.
+               When written, this file sets the number of the startup profile
+               and the device activates this profile immediately.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/info
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               The data is 6 bytes long.
+               This file is readonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/key_mask
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one deactivate certain keys like
+               windows and application keys, to prevent accidental presses.
+               Profile number for which this settings occur is included in
+               written data. The data has to be 6 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_capslock
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               capslock key for a specific profile. Profile number is included
+               in written data. The data has to be 6 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_easyzone
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               easyzone keys for a specific profile. Profile number is included
+               in written data. The data has to be 65 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_function
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               function keys for a specific profile. Profile number is included
+               in written data. The data has to be 41 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_macro
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the macro
+               keys for a specific profile. Profile number is included in
+               written data. The data has to be 35 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_media
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the media
+               keys for a specific profile. Profile number is included in
+               written data. The data has to be 29 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_thumbster
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               thumbster keys for a specific profile. Profile number is included
+               in written data. The data has to be 23 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/last_set
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the time in secs since
+               epoch in which the last configuration took place.
+               The data has to be 20 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/light
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the backlight intensity for
+               a specific profile. Profile number is included in written data.
+               The data has to be 10 bytes long for Isku, IskuFX needs 16 bytes
+               of data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/macro
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one store macros with max 500
+               keystrokes for a specific button for a specific profile.
+               Button and profile numbers are included in written data.
+               The data has to be 2083 bytes long.
+               Before reading this file, control has to be written to select
+               which profile and key to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/reset
+Date:          November 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one reset the device.
+               The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one select which data from which
+               profile will be read next. The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talk
+Date:          June 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one trigger easyshift functionality
+               from the host.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talkfx
+Date:          February 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one trigger temporary color schemes
+               from the host.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
index 833fd59926a73c1f3725559400b60b598f2446fa..545e69f432292aa3051a0f14e6880d51ca6f257c 100644 (file)
@@ -1,3 +1,14 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The integer value of this attribute ranges from 0-4.
+                When read, this attribute returns the number of the actual
+                profile. This value is persistent, so its equivalent to the
+                profile that's active when the mouse is powered on next time.
+               When written, this file sets the number of the startup profile
+               and the mouse activates this profile immediately.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
 Date:          October 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -22,6 +33,40 @@ Description: When read, this file returns the raw integer version number of the
                Please read binary attribute info which contains firmware version.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/info
+Date:          November 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               When written, the device can be reset.
+               The data is 8 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store a macro with max 500 key/button strokes
+               internally.
+               When written, this file lets one set the sequence for a specific
+               button for a specific profile. Button and profile numbers are
+               included in written data. The data has to be 2082 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_buttons
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds information about button layout.
+               When written, this file lets one write the respective profile
+               buttons back to the mouse. The data has to be 77 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -34,6 +79,22 @@ Description: The mouse can store 5 profiles which can be switched by the
                Write control to select profile and read profile_buttons instead.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds information like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 43 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -45,4 +106,40 @@ Description:        The mouse can store 5 profiles which can be switched by the
                The returned data is 43 bytes in size.
                This file is readonly.
                Write control to select profile and read profile_settings instead.
-Users:         http://roccat.sourceforge.net
\ No newline at end of file
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse has a tracking- and a distance-control-unit. These
+               can be activated/deactivated and the lift-off distance can be
+               set. The data has to be 6 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/talk
+Date:          May 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   Used to active some easy* functions of the mouse from outside.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written a calibration process for the tracking control unit
+               can be initiated/cancelled. Also lets one read/write sensor
+               registers.
+               The data has to be 4 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
+Date:          October 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read the mouse returns a 30x30 pixel image of the
+               sampled underground. This works only in the course of a
+               calibration process initiated with tcu.
+               The returned data is 1028 bytes in size.
+               This file is readonly.
+Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-konepure b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-konepure
new file mode 100644 (file)
index 0000000..41a9b7f
--- /dev/null
@@ -0,0 +1,105 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/actual_profile
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. actual_profile holds number of actual profile.
+               This value is persistent, so its value determines the profile
+               that's active when the mouse is powered on next time.
+               When written, the mouse activates the set profile immediately.
+               The data has to be 3 bytes long.
+               The mouse will reject invalid data.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/control
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one select which data from which
+               profile will be read next. The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/info
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               When written, the device can be reset.
+               The data is 6 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/macro
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store a macro with max 500 key/button strokes
+               internally.
+               When written, this file lets one set the sequence for a specific
+               button for a specific profile. Button and profile numbers are
+               included in written data. The data has to be 2082 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_buttons
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds information about button layout.
+               When written, this file lets one write the respective profile
+               buttons back to the mouse. The data has to be 59 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_settings
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds information like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 31 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/sensor
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse has a tracking- and a distance-control-unit. These
+               can be activated/deactivated and the lift-off distance can be
+               set. The data has to be 6 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/talk
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   Used to active some easy* functions of the mouse from outside.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written a calibration process for the tracking control unit
+               can be initiated/cancelled. Also lets one read/write sensor
+               registers.
+               The data has to be 4 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu_image
+Date:          December 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read the mouse returns a 30x30 pixel image of the
+               sampled underground. This works only in the course of a
+               calibration process initiated with tcu.
+               The returned data is 1028 bytes in size.
+               This file is readonly.
+Users:         http://roccat.sourceforge.net
index 4a98e02b6c6a969460d050dfcff5ab16f7d52a54..ab01631e1e0f2828c05841a4a645b85a3d38885c 100644 (file)
@@ -8,6 +8,17 @@ Description:   The integer value of this attribute ranges from 1-4.
                Has never been used. If bookkeeping is done, it's done in userland tools.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_profile
+Date:          January 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The integer value of this attribute ranges from 0-4.
+               When read, this attribute returns the number of the active
+               profile.
+               When written, the mouse activates this profile immediately.
+               The profile that's active when powered down is the same that's
+               active when the mouse is powered on.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_x
 Date:          January 2011
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -40,6 +51,29 @@ Description: When read, this file returns the raw integer version number of the
                Obsoleted by binary sysfs attribute "info".
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/info
+Date:          November 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               When written, the device can be reset.
+               The data is 6 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
+Date:          January 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds information about button layout.
+               When written, this file lets one write the respective profile
+               buttons back to the mouse. The data has to be 23 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_buttons
 Date:          January 2011
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -52,6 +86,22 @@ Description: The mouse can store 5 profiles which can be switched by the
                Write control to select profile and read profile_buttons instead.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
+Date:          January 2011
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds information like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 16 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_settings
 Date:          January 2011
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-lua b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-lua
new file mode 100644 (file)
index 0000000..31c6c4c
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/control
+Date:          October 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, cpi, button and light settings can be configured.
+               When read, actual cpi setting and sensor data are returned.
+               The data has to be 8 bytes long.
+Users:         http://roccat.sourceforge.net
index 87ac87e9556dbce80da807efed3baa084574215a..16020b31ae640eddda12cae66d54f48a7c4cb65b 100644 (file)
@@ -37,6 +37,29 @@ Description: When read, this file returns the raw integer version number of the
                Please use binary attribute "info" which provides this information.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/info
+Date:          November 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               When written, the device can be reset.
+               The data is 6 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_buttons holds information about button layout.
+               When written, this file lets one write the respective profile
+               buttons back to the mouse. The data has to be 19 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -49,6 +72,22 @@ Description: The mouse can store 5 profiles which can be switched by the
                Write control to select profile and read profile_buttons instead.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split in settings and buttons.
+               profile_settings holds information like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 13 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
@@ -62,6 +101,17 @@ Description:        The mouse can store 5 profiles which can be switched by the
                Write control to select profile and read profile_settings instead.
 Users:         http://roccat.sourceforge.net
 
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
+Date:          August 2010
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns the settings stored in the mouse.
+               The size of the data is 3 bytes and holds information on the
+               startup_profile.
+               When written, this file lets write settings back to the mouse.
+               The data has to be 3 bytes long. The mouse will reject invalid
+               data.
+Users:         http://roccat.sourceforge.net
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
 Date:          August 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-ryos b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-ryos
new file mode 100644 (file)
index 0000000..1d6a8cf
--- /dev/null
@@ -0,0 +1,178 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/control
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one select which data from which
+               profile will be read next. The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/profile
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. profile holds index of actual profile.
+               This value is persistent, so its value determines the profile
+               that's active when the device is powered on next time.
+               When written, the device activates the set profile immediately.
+               The data has to be 3 bytes long.
+               The device will reject invalid data.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_primary
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the default of all keys for
+               a specific profile. Profile index is included in written data.
+               The data has to be 125 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_function
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               function keys for a specific profile. Profile index is included
+               in written data. The data has to be 95 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_macro
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the macro
+               keys for a specific profile. Profile index is included in
+               written data. The data has to be 35 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_thumbster
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               thumbster keys for a specific profile. Profile index is included
+               in written data. The data has to be 23 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_extra
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               capslock and function keys for a specific profile. Profile index
+               is included in written data. The data has to be 8 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_easyzone
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the function of the
+               easyzone keys for a specific profile. Profile index is included
+               in written data. The data has to be 294 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/key_mask
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one deactivate certain keys like
+               windows and application keys, to prevent accidental presses.
+               Profile index for which this settings occur is included in
+               written data. The data has to be 6 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the backlight intensity for
+               a specific profile. Profile index is included in written data.
+               This attribute is only valid for the glow and pro variant.
+               The data has to be 16 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/macro
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one store macros with max 480
+               keystrokes for a specific button for a specific profile.
+               Button and profile indexes are included in written data.
+               The data has to be 2002 bytes long.
+               Before reading this file, control has to be written to select
+               which profile and key to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/info
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               The data is 8 bytes long.
+               This file is readonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/reset
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one reset the device.
+               The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/talk
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one trigger easyshift functionality
+               from the host.
+               The data has to be 16 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light_control
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one switch between stored and custom
+               light settings.
+               This attribute is only valid for the pro variant.
+               The data has to be 8 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/stored_lights
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set per-key lighting for different
+               layers.
+               This attribute is only valid for the pro variant.
+               The data has to be 1382 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/custom_lights
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set the actual per-key lighting.
+               This attribute is only valid for the pro variant.
+               The data has to be 20 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light_macro
+Date:          October 2013
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one set a light macro that is looped
+               whenever the device gets in dimness mode.
+               This attribute is only valid for the pro variant.
+               The data has to be 2002 bytes long.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-savu b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-savu
new file mode 100644 (file)
index 0000000..f1e02a9
--- /dev/null
@@ -0,0 +1,76 @@
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/buttons
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split into general settings and
+               button settings. buttons holds informations about button layout.
+               When written, this file lets one write the respective profile
+               buttons to the mouse. The data has to be 47 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               Before reading this file, control has to be written to select
+               which profile to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/control
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one select which data from which
+               profile will be read next. The data has to be 3 bytes long.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/general
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. A profile is split into general settings and
+               button settings. profile holds informations like resolution, sensitivity
+               and light effects.
+               When written, this file lets one write the respective profile
+               settings back to the mouse. The data has to be 43 bytes long.
+               The mouse will reject invalid data.
+               Which profile to write is determined by the profile number
+               contained in the data.
+               This file is writeonly.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/info
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When read, this file returns general data like firmware version.
+               When written, the device can be reset.
+               The data is 8 bytes long.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   When written, this file lets one store macros with max 500
+               keystrokes for a specific button for a specific profile.
+               Button and profile numbers are included in written data.
+               The data has to be 2083 bytes long.
+               Before reading this file, control has to be written to select
+               which profile and key to read.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/profile
+Date:          Mai 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse can store 5 profiles which can be switched by the
+               press of a button. profile holds number of actual profile.
+               This value is persistent, so its value determines the profile
+               that's active when the mouse is powered on next time.
+               When written, the mouse activates the set profile immediately.
+               The data has to be 3 bytes long.
+               The mouse will reject invalid data.
+Users:         http://roccat.sourceforge.net
+
+What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/sensor
+Date:          July 2012
+Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:   The mouse has a Avago ADNS-3090 sensor.
+               This file allows reading and writing of the mouse sensors registers.
+               The data has to be 4 bytes long.
+Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-corsair b/Documentation/ABI/testing/sysfs-driver-hid-corsair
new file mode 100644 (file)
index 0000000..b8827f0
--- /dev/null
@@ -0,0 +1,15 @@
+What:          /sys/bus/drivers/corsair/<dev>/macro_mode
+Date:          August 2015
+KernelVersion: 4.2
+Contact:       Clement Vuchener <clement.vuchener@gmail.com>
+Description:   Get/set the current playback mode. "SW" for software mode
+               where G-keys triggers their regular key codes. "HW" for
+               hardware playback mode where the G-keys play their macro
+               from the on-board memory.
+
+
+What:          /sys/bus/drivers/corsair/<dev>/current_profile
+Date:          August 2015
+KernelVersion: 4.2
+Contact:       Clement Vuchener <clement.vuchener@gmail.com>
+Description:   Get/set the current selected profile. Values are from 1 to 3.
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo b/Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo
deleted file mode 100644 (file)
index 55e281b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/actual_profile
-Date:          Januar 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The integer value of this attribute ranges from 1-5.
-               When read, this attribute returns the number of the actual
-               profile which is also the profile that's active on device startup.
-               When written this attribute activates the selected profile
-               immediately.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/button
-Date:          Januar 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The keyboard can store short macros with consist of 1 button with
-               several modifier keys internally.
-               When written, this file lets one set the sequence for a specific
-               button for a specific profile. Button and profile numbers are
-               included in written data. The data has to be 24 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/info
-Date:          Januar 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns some info about the device like the
-               installed firmware version.
-               The size of the data is 8 bytes in size.
-               This file is readonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/key_mask
-Date:          Januar 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The keyboard lets the user deactivate 5 certain keys like the
-               windows and application keys, to protect the user from the outcome
-               of accidentally pressing them.
-               The integer value of this attribute has bits 0-4 set depending
-               on the state of the corresponding key.
-               When read, this file returns the current state of the buttons.
-               When written, the given buttons are activated/deactivated
-               immediately.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/mode_key
-Date:          Januar 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The keyboard has a condensed layout without num-lock key.
-               Instead it uses a mode-key which activates a gaming mode where
-               the assignment of the number block changes.
-               The integer value of this attribute ranges from 0 (OFF) to 1 (ON).
-               When read, this file returns the actual state of the key.
-               When written, the key is activated/deactivated immediately.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
deleted file mode 100644 (file)
index c601d0f..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/actual_profile
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The integer value of this attribute ranges from 0-4.
-               When read, this attribute returns the number of the actual
-               profile. This value is persistent, so its equivalent to the
-               profile that's active when the device is powered on next time.
-               When written, this file sets the number of the startup profile
-               and the device activates this profile immediately.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/info
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               The data is 6 bytes long.
-               This file is readonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/key_mask
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one deactivate certain keys like
-               windows and application keys, to prevent accidental presses.
-               Profile number for which this settings occur is included in
-               written data. The data has to be 6 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_capslock
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               capslock key for a specific profile. Profile number is included
-               in written data. The data has to be 6 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_easyzone
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               easyzone keys for a specific profile. Profile number is included
-               in written data. The data has to be 65 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_function
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               function keys for a specific profile. Profile number is included
-               in written data. The data has to be 41 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_macro
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the macro
-               keys for a specific profile. Profile number is included in
-               written data. The data has to be 35 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_media
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the media
-               keys for a specific profile. Profile number is included in
-               written data. The data has to be 29 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_thumbster
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               thumbster keys for a specific profile. Profile number is included
-               in written data. The data has to be 23 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/last_set
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the time in secs since
-               epoch in which the last configuration took place.
-               The data has to be 20 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/light
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the backlight intensity for
-               a specific profile. Profile number is included in written data.
-               The data has to be 10 bytes long for Isku, IskuFX needs 16 bytes
-               of data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/macro
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one store macros with max 500
-               keystrokes for a specific button for a specific profile.
-               Button and profile numbers are included in written data.
-               The data has to be 2083 bytes long.
-               Before reading this file, control has to be written to select
-               which profile and key to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/reset
-Date:          November 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one reset the device.
-               The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one select which data from which
-               profile will be read next. The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talk
-Date:          June 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one trigger easyshift functionality
-               from the host.
-               The data has to be 16 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talkfx
-Date:          February 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one trigger temporary color schemes
-               from the host.
-               The data has to be 16 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
deleted file mode 100644 (file)
index 7bd776f..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The integer value of this attribute ranges from 0-4.
-                When read, this attribute returns the number of the actual
-                profile. This value is persistent, so its equivalent to the
-                profile that's active when the mouse is powered on next time.
-               When written, this file sets the number of the startup profile
-               and the mouse activates this profile immediately.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/info
-Date:          November 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               When written, the device can be reset.
-               The data is 8 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store a macro with max 500 key/button strokes
-               internally.
-               When written, this file lets one set the sequence for a specific
-               button for a specific profile. Button and profile numbers are
-               included in written data. The data has to be 2082 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_buttons
-Date:          August 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_buttons holds information about button layout.
-               When written, this file lets one write the respective profile
-               buttons back to the mouse. The data has to be 77 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_settings holds information like resolution, sensitivity
-               and light effects.
-               When written, this file lets one write the respective profile
-               settings back to the mouse. The data has to be 43 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse has a tracking- and a distance-control-unit. These
-               can be activated/deactivated and the lift-off distance can be
-               set. The data has to be 6 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/talk
-Date:          May 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   Used to active some easy* functions of the mouse from outside.
-               The data has to be 16 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written a calibration process for the tracking control unit
-               can be initiated/cancelled. Also lets one read/write sensor
-               registers.
-               The data has to be 4 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
-Date:          October 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read the mouse returns a 30x30 pixel image of the
-               sampled underground. This works only in the course of a
-               calibration process initiated with tcu.
-               The returned data is 1028 bytes in size.
-               This file is readonly.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure b/Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure
deleted file mode 100644 (file)
index 41a9b7f..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/actual_profile
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. actual_profile holds number of actual profile.
-               This value is persistent, so its value determines the profile
-               that's active when the mouse is powered on next time.
-               When written, the mouse activates the set profile immediately.
-               The data has to be 3 bytes long.
-               The mouse will reject invalid data.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/control
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one select which data from which
-               profile will be read next. The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/info
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               When written, the device can be reset.
-               The data is 6 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/macro
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store a macro with max 500 key/button strokes
-               internally.
-               When written, this file lets one set the sequence for a specific
-               button for a specific profile. Button and profile numbers are
-               included in written data. The data has to be 2082 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_buttons
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_buttons holds information about button layout.
-               When written, this file lets one write the respective profile
-               buttons back to the mouse. The data has to be 59 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_settings
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_settings holds information like resolution, sensitivity
-               and light effects.
-               When written, this file lets one write the respective profile
-               settings back to the mouse. The data has to be 31 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/sensor
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse has a tracking- and a distance-control-unit. These
-               can be activated/deactivated and the lift-off distance can be
-               set. The data has to be 6 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/talk
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   Used to active some easy* functions of the mouse from outside.
-               The data has to be 16 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written a calibration process for the tracking control unit
-               can be initiated/cancelled. Also lets one read/write sensor
-               registers.
-               The data has to be 4 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu_image
-Date:          December 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read the mouse returns a 30x30 pixel image of the
-               sampled underground. This works only in the course of a
-               calibration process initiated with tcu.
-               The returned data is 1028 bytes in size.
-               This file is readonly.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus
deleted file mode 100644 (file)
index a10404f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_profile
-Date:          January 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The integer value of this attribute ranges from 0-4.
-               When read, this attribute returns the number of the active
-               profile.
-               When written, the mouse activates this profile immediately.
-               The profile that's active when powered down is the same that's
-               active when the mouse is powered on.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/info
-Date:          November 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               When written, the device can be reset.
-               The data is 6 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
-Date:          January 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_buttons holds information about button layout.
-               When written, this file lets one write the respective profile
-               buttons back to the mouse. The data has to be 23 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
-Date:          January 2011
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_settings holds information like resolution, sensitivity
-               and light effects.
-               When written, this file lets one write the respective profile
-               settings back to the mouse. The data has to be 16 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-lua b/Documentation/ABI/testing/sysfs-driver-hid-roccat-lua
deleted file mode 100644 (file)
index 31c6c4c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/control
-Date:          October 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, cpi, button and light settings can be configured.
-               When read, actual cpi setting and sensor data are returned.
-               The data has to be 8 bytes long.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
deleted file mode 100644 (file)
index 9fa9de3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/info
-Date:          November 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               When written, the device can be reset.
-               The data is 6 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings
-Date:          August 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_settings holds information like resolution, sensitivity
-               and light effects.
-               When written, this file lets one write the respective profile
-               settings back to the mouse. The data has to be 13 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons
-Date:          August 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split in settings and buttons.
-               profile_buttons holds information about button layout.
-               When written, this file lets one write the respective profile
-               buttons back to the mouse. The data has to be 19 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
-Date:          August 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns the settings stored in the mouse.
-               The size of the data is 3 bytes and holds information on the
-               startup_profile.
-               When written, this file lets write settings back to the mouse.
-               The data has to be 3 bytes long. The mouse will reject invalid
-               data.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-ryos b/Documentation/ABI/testing/sysfs-driver-hid-roccat-ryos
deleted file mode 100644 (file)
index 1d6a8cf..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/control
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one select which data from which
-               profile will be read next. The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/profile
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. profile holds index of actual profile.
-               This value is persistent, so its value determines the profile
-               that's active when the device is powered on next time.
-               When written, the device activates the set profile immediately.
-               The data has to be 3 bytes long.
-               The device will reject invalid data.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_primary
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the default of all keys for
-               a specific profile. Profile index is included in written data.
-               The data has to be 125 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_function
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               function keys for a specific profile. Profile index is included
-               in written data. The data has to be 95 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_macro
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the macro
-               keys for a specific profile. Profile index is included in
-               written data. The data has to be 35 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_thumbster
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               thumbster keys for a specific profile. Profile index is included
-               in written data. The data has to be 23 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_extra
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               capslock and function keys for a specific profile. Profile index
-               is included in written data. The data has to be 8 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/keys_easyzone
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the function of the
-               easyzone keys for a specific profile. Profile index is included
-               in written data. The data has to be 294 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/key_mask
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one deactivate certain keys like
-               windows and application keys, to prevent accidental presses.
-               Profile index for which this settings occur is included in
-               written data. The data has to be 6 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the backlight intensity for
-               a specific profile. Profile index is included in written data.
-               This attribute is only valid for the glow and pro variant.
-               The data has to be 16 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/macro
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one store macros with max 480
-               keystrokes for a specific button for a specific profile.
-               Button and profile indexes are included in written data.
-               The data has to be 2002 bytes long.
-               Before reading this file, control has to be written to select
-               which profile and key to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/info
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               The data is 8 bytes long.
-               This file is readonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/reset
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one reset the device.
-               The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/talk
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one trigger easyshift functionality
-               from the host.
-               The data has to be 16 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light_control
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one switch between stored and custom
-               light settings.
-               This attribute is only valid for the pro variant.
-               The data has to be 8 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/stored_lights
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set per-key lighting for different
-               layers.
-               This attribute is only valid for the pro variant.
-               The data has to be 1382 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/custom_lights
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set the actual per-key lighting.
-               This attribute is only valid for the pro variant.
-               The data has to be 20 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/light_macro
-Date:          October 2013
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one set a light macro that is looped
-               whenever the device gets in dimness mode.
-               This attribute is only valid for the pro variant.
-               The data has to be 2002 bytes long.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu b/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu
deleted file mode 100644 (file)
index f1e02a9..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/buttons
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split into general settings and
-               button settings. buttons holds informations about button layout.
-               When written, this file lets one write the respective profile
-               buttons to the mouse. The data has to be 47 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               Before reading this file, control has to be written to select
-               which profile to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/control
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one select which data from which
-               profile will be read next. The data has to be 3 bytes long.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/general
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. A profile is split into general settings and
-               button settings. profile holds informations like resolution, sensitivity
-               and light effects.
-               When written, this file lets one write the respective profile
-               settings back to the mouse. The data has to be 43 bytes long.
-               The mouse will reject invalid data.
-               Which profile to write is determined by the profile number
-               contained in the data.
-               This file is writeonly.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/info
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns general data like firmware version.
-               When written, the device can be reset.
-               The data is 8 bytes long.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When written, this file lets one store macros with max 500
-               keystrokes for a specific button for a specific profile.
-               Button and profile numbers are included in written data.
-               The data has to be 2083 bytes long.
-               Before reading this file, control has to be written to select
-               which profile and key to read.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/profile
-Date:          Mai 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse can store 5 profiles which can be switched by the
-               press of a button. profile holds number of actual profile.
-               This value is persistent, so its value determines the profile
-               that's active when the mouse is powered on next time.
-               When written, the mouse activates the set profile immediately.
-               The data has to be 3 bytes long.
-               The mouse will reject invalid data.
-Users:         http://roccat.sourceforge.net
-
-What:          /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/sensor
-Date:          July 2012
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   The mouse has a Avago ADNS-3090 sensor.
-               This file allows reading and writing of the mouse sensors registers.
-               The data has to be 4 bytes long.
-Users:         http://roccat.sourceforge.net
index e94a10bb4a9e9d0f6fb9ff3e1aa47af4892f11c2..53f439dcc94b7d4e3a7c9ba237f03e94519c1315 100644 (file)
 !Esound/soc/soc-devres.c
 !Esound/soc/soc-io.c
 !Esound/soc/soc-pcm.c
+!Esound/soc/soc-ops.c
+!Esound/soc/soc-compress.c
      </sect1>
      <sect1><title>ASoC DAPM API</title>
 !Esound/soc/soc-dapm.c
index 84ef6a90131c2ea44410f9f3c53f6b56a499bfe5..a27ab9f53fb68a62652bff8ed847322a838cd41d 100644 (file)
@@ -2181,10 +2181,6 @@ struct _snd_pcm_runtime {
        struct snd_pcm_hardware hw;
        struct snd_pcm_hw_constraints hw_constraints;
 
-       /* -- interrupt callbacks -- */
-       void (*transfer_ack_begin)(struct snd_pcm_substream *substream);
-       void (*transfer_ack_end)(struct snd_pcm_substream *substream);
-
        /* -- timer -- */
        unsigned int timer_resolution;  /* timer resolution */
 
@@ -2209,9 +2205,8 @@ struct _snd_pcm_runtime {
          For the operators (callbacks) of each sound driver, most of
        these records are supposed to be read-only.  Only the PCM
        middle-layer changes / updates them.  The exceptions are
-       the hardware description (hw), interrupt callbacks
-       (transfer_ack_xxx), DMA buffer information, and the private
-       data.  Besides, if you use the standard buffer allocation
+       the hardware description (hw) DMA buffer information and the
+       private data.  Besides, if you use the standard buffer allocation
        method via <function>snd_pcm_lib_malloc_pages()</function>,
        you don't need to set the DMA buffer information by yourself.
        </para>
@@ -2538,16 +2533,6 @@ struct _snd_pcm_runtime {
         </para>
        </section>
 
-       <section id="pcm-interface-runtime-intr">
-       <title>Interrupt Callbacks</title>
-       <para>
-       The field <structfield>transfer_ack_begin</structfield> and
-       <structfield>transfer_ack_end</structfield> are called at
-       the beginning and at the end of
-       <function>snd_pcm_period_elapsed()</function>, respectively. 
-       </para>
-       </section>
-
     </section>
 
     <section id="pcm-interface-operators">
diff --git a/Documentation/devicetree/bindings/arc/archs-idu-intc.txt b/Documentation/devicetree/bindings/arc/archs-idu-intc.txt
deleted file mode 100644 (file)
index 0dcb7c7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-* ARC-HS Interrupt Distribution Unit
-
-  This optional 2nd level interrupt controller can be used in SMP configurations for
-  dynamic IRQ routing, load balancing of common/external IRQs towards core intc.
-
-Properties:
-
-- compatible: "snps,archs-idu-intc"
-- interrupt-controller: This is an interrupt controller.
-- interrupt-parent: <reference to parent core intc>
-- #interrupt-cells: Must be <2>.
-- interrupts: <...> specifies the upstream core irqs
-
-  First cell specifies the "common" IRQ from peripheral to IDU
-  Second cell specifies the irq distribution mode to cores
-     0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3
-
-  intc accessed via the special ARC AUX register interface, hence "reg" property
-  is not specified.
-
-Example:
-       core_intc: core-interrupt-controller {
-               compatible = "snps,archs-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-       };
-
-       idu_intc: idu-interrupt-controller {
-               compatible = "snps,archs-idu-intc";
-               interrupt-controller;
-               interrupt-parent = <&core_intc>;
-
-               /*
-                * <hwirq  distribution>
-                * distribution: 0=RR; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3
-                */
-               #interrupt-cells = <2>;
-
-               /* upstream core irqs: downstream these are "COMMON" irq 0,1..  */
-               interrupts = <24 25 26 27 28 29 30 31>;
-       };
-
-       some_device: serial@c0fc1000 {
-               interrupt-parent = <&idu_intc>;
-               interrupts = <0 0>;     /* upstream idu IRQ #24, Round Robin */
-       };
diff --git a/Documentation/devicetree/bindings/arc/archs-intc.txt b/Documentation/devicetree/bindings/arc/archs-intc.txt
deleted file mode 100644 (file)
index 69f326d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-* ARC-HS incore Interrupt Controller (Provided by cores implementing ARCv2 ISA)
-
-Properties:
-
-- compatible: "snps,archs-intc"
-- interrupt-controller: This is an interrupt controller.
-- #interrupt-cells: Must be <1>.
-
-  Single Cell "interrupts" property of a device specifies the IRQ number
-  between 16 to 256
-
-  intc accessed via the special ARC AUX register interface, hence "reg" property
-  is not specified.
-
-Example:
-
-       intc: interrupt-controller {
-               compatible = "snps,archs-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               interrupts = <16 17 18 19 20 21 22 23 24 25>;
-       };
diff --git a/Documentation/devicetree/bindings/arc/interrupts.txt b/Documentation/devicetree/bindings/arc/interrupts.txt
deleted file mode 100644 (file)
index 9a5d562..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-* ARC700 incore Interrupt Controller
-
-  The core interrupt controller provides 32 prioritised interrupts (2 levels)
-  to ARC700 core.
-
-Properties:
-
-- compatible: "snps,arc700-intc"
-- interrupt-controller: This is an interrupt controller.
-- #interrupt-cells: Must be <1>.
-
-  Single Cell "interrupts" property of a device specifies the IRQ number
-  between 0 to 31
-
-  intc accessed via the special ARC AUX register interface, hence "reg" property
-  is not specified.
-
-Example:
-
-       intc: interrupt-controller {
-               compatible = "snps,arc700-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/calxeda/combophy.txt b/Documentation/devicetree/bindings/arm/calxeda/combophy.txt
deleted file mode 100644 (file)
index 6622bdb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Calxeda Highbank Combination Phys for SATA
-
-Properties:
-- compatible : Should be "calxeda,hb-combophy"
-- #phy-cells: Should be 1.
-- reg : Address and size for Combination Phy registers.
-- phydev: device ID for programming the combophy.
-
-Example:
-
-       combophy5: combo-phy@fff5d000 {
-               compatible = "calxeda,hb-combophy";
-               #phy-cells = <1>;
-               reg = <0xfff5d000 0x1000>;
-               phydev = <31>;
-       };
-
diff --git a/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt
deleted file mode 100644 (file)
index 0496759..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Calxeda DDR memory controller
-
-Properties:
-- compatible : Should be:
-  - "calxeda,hb-ddr-ctrl" for ECX-1000
-  - "calxeda,ecx-2000-ddr-ctrl" for ECX-2000
-- reg : Address and size for DDR controller registers.
-- interrupts : Interrupt for DDR controller.
-
-Example:
-
-       memory-controller@fff00000 {
-               compatible = "calxeda,hb-ddr-ctrl";
-               reg = <0xfff00000 0x1000>;
-               interrupts = <0 91 4>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt b/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt
deleted file mode 100644 (file)
index 597e8a0..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* TI Common Platform Interrupt Controller
-
-Common Platform Interrupt Controller (cp_intc) is used on
-OMAP-L1x SoCs and can support several configurable number
-of interrupts.
-
-Main node required properties:
-
-- compatible : should be:
-       "ti,cp-intc"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The type shall be a <u32> and the value shall be 1.
-
-  The cell contains the interrupt number in the range [0-128].
-- ti,intc-size: Number of interrupts handled by the interrupt controller.
-- reg: physical base address and size of the intc registers map.
-
-Example:
-
-       intc: interrupt-controller@1 {
-               compatible = "ti,cp-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               ti,intc-size = <101>;
-               reg = <0xfffee000 0x2000>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/gic-v3.txt b/Documentation/devicetree/bindings/arm/gic-v3.txt
deleted file mode 100644 (file)
index 7803e77..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-* ARM Generic Interrupt Controller, version 3
-
-AArch64 SMP cores are often associated with a GICv3, providing Private
-Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
-Software Generated Interrupts (SGI), and Locality-specific Peripheral
-Interrupts (LPI).
-
-Main node required properties:
-
-- compatible : should at least contain  "arm,gic-v3".
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. Must be a single cell with a value of at least 3.
-
-  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
-  interrupts. Other values are reserved for future use.
-
-  The 2nd cell contains the interrupt number for the interrupt type.
-  SPI interrupts are in the range [0-987]. PPI interrupts are in the
-  range [0-15].
-
-  The 3rd cell is the flags, encoded as follows:
-       bits[3:0] trigger type and level flags.
-               1 = edge triggered
-               4 = level triggered
-
-  Cells 4 and beyond are reserved for future use. When the 1st cell
-  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
-  ignored. It is recommended that padding cells have a value of 0.
-
-- reg : Specifies base physical address(s) and size of the GIC
-  registers, in the following order:
-  - GIC Distributor interface (GICD)
-  - GIC Redistributors (GICR), one range per redistributor region
-  - GIC CPU interface (GICC)
-  - GIC Hypervisor interface (GICH)
-  - GIC Virtual CPU interface (GICV)
-
-  GICC, GICH and GICV are optional.
-
-- interrupts : Interrupt source of the VGIC maintenance interrupt.
-
-Optional
-
-- redistributor-stride : If using padding pages, specifies the stride
-  of consecutive redistributors. Must be a multiple of 64kB.
-
-- #redistributor-regions: The number of independent contiguous regions
-  occupied by the redistributors. Required if more than one such
-  region is present.
-
-Sub-nodes:
-
-GICv3 has one or more Interrupt Translation Services (ITS) that are
-used to route Message Signalled Interrupts (MSI) to the CPUs.
-
-These nodes must have the following properties:
-- compatible : Should at least contain  "arm,gic-v3-its".
-- msi-controller : Boolean property. Identifies the node as an MSI controller
-- #msi-cells: Must be <1>. The single msi-cell is the DeviceID of the device
-  which will generate the MSI.
-- reg: Specifies the base physical address and size of the ITS
-  registers.
-
-The main GIC node must contain the appropriate #address-cells,
-#size-cells and ranges properties for the reg property of all ITS
-nodes.
-
-Examples:
-
-       gic: interrupt-controller@2cf00000 {
-               compatible = "arm,gic-v3";
-               #interrupt-cells = <3>;
-               #address-cells = <2>;
-               #size-cells = <2>;
-               ranges;
-               interrupt-controller;
-               reg = <0x0 0x2f000000 0 0x10000>,       // GICD
-                     <0x0 0x2f100000 0 0x200000>,      // GICR
-                     <0x0 0x2c000000 0 0x2000>,        // GICC
-                     <0x0 0x2c010000 0 0x2000>,        // GICH
-                     <0x0 0x2c020000 0 0x2000>;        // GICV
-               interrupts = <1 9 4>;
-
-               gic-its@2c200000 {
-                       compatible = "arm,gic-v3-its";
-                       msi-controller;
-                       #msi-cells = <1>;
-                       reg = <0x0 0x2c200000 0 0x200000>;
-               };
-       };
-
-       gic: interrupt-controller@2c010000 {
-               compatible = "arm,gic-v3";
-               #interrupt-cells = <3>;
-               #address-cells = <2>;
-               #size-cells = <2>;
-               ranges;
-               interrupt-controller;
-               redistributor-stride = <0x0 0x40000>;   // 256kB stride
-               #redistributor-regions = <2>;
-               reg = <0x0 0x2c010000 0 0x10000>,       // GICD
-                     <0x0 0x2d000000 0 0x800000>,      // GICR 1: CPUs 0-31
-                     <0x0 0x2e000000 0 0x800000>;      // GICR 2: CPUs 32-63
-                     <0x0 0x2c040000 0 0x2000>,        // GICC
-                     <0x0 0x2c060000 0 0x2000>,        // GICH
-                     <0x0 0x2c080000 0 0x2000>;        // GICV
-               interrupts = <1 9 4>;
-
-               gic-its@2c200000 {
-                       compatible = "arm,gic-v3-its";
-                       msi-controller;
-                       #msi-cells = <1>;
-                       reg = <0x0 0x2c200000 0 0x200000>;
-               };
-
-               gic-its@2c400000 {
-                       compatible = "arm,gic-v3-its";
-                       msi-controller;
-                       #msi-cells = <1>;
-                       reg = <0x0 0x2c400000 0 0x200000>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
deleted file mode 100644 (file)
index cc56021..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-* ARM Generic Interrupt Controller
-
-ARM SMP cores are often associated with a GIC, providing per processor
-interrupts (PPI), shared processor interrupts (SPI) and software
-generated interrupts (SGI).
-
-Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
-Secondary GICs are cascaded into the upward interrupt controller and do not
-have PPIs or SGIs.
-
-Main node required properties:
-
-- compatible : should be one of:
-       "arm,arm1176jzf-devchip-gic"
-       "arm,arm11mp-gic"
-       "arm,cortex-a15-gic"
-       "arm,cortex-a7-gic"
-       "arm,cortex-a9-gic"
-       "arm,gic-400"
-       "arm,pl390"
-       "brcm,brahma-b15-gic"
-       "qcom,msm-8660-qgic"
-       "qcom,msm-qgic2"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source.  The type shall be a <u32> and the value shall be 3.
-
-  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
-  interrupts.
-
-  The 2nd cell contains the interrupt number for the interrupt type.
-  SPI interrupts are in the range [0-987].  PPI interrupts are in the
-  range [0-15].
-
-  The 3rd cell is the flags, encoded as follows:
-       bits[3:0] trigger type and level flags.
-               1 = low-to-high edge triggered
-               2 = high-to-low edge triggered (invalid for SPIs)
-               4 = active high level-sensitive
-               8 = active low level-sensitive (invalid for SPIs).
-       bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of
-       the 8 possible cpus attached to the GIC.  A bit set to '1' indicated
-       the interrupt is wired to that CPU.  Only valid for PPI interrupts.
-       Also note that the configurability of PPI interrupts is IMPLEMENTATION
-       DEFINED and as such not guaranteed to be present (most SoC available
-       in 2014 seem to ignore the setting of this flag and use the hardware
-       default value).
-
-- reg : Specifies base physical address(s) and size of the GIC registers. The
-  first region is the GIC distributor register base and size. The 2nd region is
-  the GIC cpu interface register base and size.
-
-Optional
-- interrupts   : Interrupt source of the parent interrupt controller on
-  secondary GICs, or VGIC maintenance interrupt on primary GIC (see
-  below).
-
-- cpu-offset   : per-cpu offset within the distributor and cpu interface
-  regions, used when the GIC doesn't have banked registers. The offset is
-  cpu-offset * cpu-nr.
-
-- clocks        : List of phandle and clock-specific pairs, one for each entry
-  in clock-names.
-- clock-names   : List of names for the GIC clock input(s). Valid clock names
-  depend on the GIC variant:
-       "ic_clk" (for "arm,arm11mp-gic")
-       "PERIPHCLKEN" (for "arm,cortex-a15-gic")
-       "PERIPHCLK", "PERIPHCLKEN" (for "arm,cortex-a9-gic")
-       "clk" (for "arm,gic-400")
-       "gclk" (for "arm,pl390")
-
-- power-domains : A phandle and PM domain specifier as defined by bindings of
-                 the power controller specified by phandle, used when the GIC
-                 is part of a Power or Clock Domain.
-
-
-Example:
-
-       intc: interrupt-controller@fff11000 {
-               compatible = "arm,cortex-a9-gic";
-               #interrupt-cells = <3>;
-               #address-cells = <1>;
-               interrupt-controller;
-               reg = <0xfff11000 0x1000>,
-                     <0xfff10100 0x100>;
-       };
-
-
-* GIC virtualization extensions (VGIC)
-
-For ARM cores that support the virtualization extensions, additional
-properties must be described (they only exist if the GIC is the
-primary interrupt controller).
-
-Required properties:
-
-- reg : Additional regions specifying the base physical address and
-  size of the VGIC registers. The first additional region is the GIC
-  virtual interface control register base and size. The 2nd additional
-  region is the GIC virtual cpu interface register base and size.
-
-- interrupts : VGIC maintenance interrupt.
-
-Example:
-
-       interrupt-controller@2c001000 {
-               compatible = "arm,cortex-a15-gic";
-               #interrupt-cells = <3>;
-               interrupt-controller;
-               reg = <0x2c001000 0x1000>,
-                     <0x2c002000 0x1000>,
-                     <0x2c004000 0x2000>,
-                     <0x2c006000 0x2000>;
-               interrupts = <1 9 0xf04>;
-       };
-
-
-* GICv2m extension for MSI/MSI-x support (Optional)
-
-Certain revisions of GIC-400 supports MSI/MSI-x via V2M register frame(s).
-This is enabled by specifying v2m sub-node(s).
-
-Required properties:
-
-- compatible       : The value here should contain "arm,gic-v2m-frame".
-
-- msi-controller    : Identifies the node as an MSI controller.
-
-- reg              : GICv2m MSI interface register base and size
-
-Optional properties:
-
-- arm,msi-base-spi  : When the MSI_TYPER register contains an incorrect
-                     value, this property should contain the SPI base of
-                     the MSI frame, overriding the HW value.
-
-- arm,msi-num-spis  : When the MSI_TYPER register contains an incorrect
-                     value, this property should contain the number of
-                     SPIs assigned to the frame, overriding the HW value.
-
-Example:
-
-       interrupt-controller@e1101000 {
-               compatible = "arm,gic-400";
-               #interrupt-cells = <3>;
-               #address-cells = <2>;
-               #size-cells = <2>;
-               interrupt-controller;
-               interrupts = <1 8 0xf04>;
-               ranges = <0 0 0 0xe1100000 0 0x100000>;
-               reg = <0x0 0xe1110000 0 0x01000>,
-                     <0x0 0xe112f000 0 0x02000>,
-                     <0x0 0xe1140000 0 0x10000>,
-                     <0x0 0xe1160000 0 0x10000>;
-               v2m0: v2m@0x8000 {
-                       compatible = "arm,gic-v2m-frame";
-                       msi-controller;
-                       reg = <0x0 0x80000 0 0x1000>;
-               };
-
-               ....
-
-               v2mN: v2m@0x9000 {
-                       compatible = "arm,gic-v2m-frame";
-                       msi-controller;
-                       reg = <0x0 0x90000 0 0x1000>;
-               };
-       };
index c733e28e18e5896cb6fa5ba4ff988a82c225780c..764c738bb3baf0bd12f8d4c9567b2bf2836b5c6e 100644 (file)
@@ -166,6 +166,23 @@ Example:
                reboot-offset = <0x4>;
        };
 
+-----------------------------------------------------------------------
+Hisilicon HiP05 PCIe-SAS system controller
+
+Required properties:
+- compatible : "hisilicon,pcie-sas-subctrl", "syscon";
+- reg : Register address and size
+
+The HiP05 PCIe-SAS system controller is shared by PCIe and SAS controllers in
+HiP05 Soc to implement some basic configurations.
+
+Example:
+       /* for HiP05 PCIe-SAS system */
+       pcie_sas: system_controller@0xb0000000 {
+               compatible = "hisilicon,pcie-sas-subctrl", "syscon";
+               reg = <0xb0000000 0x10000>;
+       };
+
 -----------------------------------------------------------------------
 Hisilicon CPU controller
 
diff --git a/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt b/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt
deleted file mode 100644 (file)
index 539adca..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-* NXP LPC32xx Main Interrupt Controller
-  (MIC, including SIC1 and SIC2 secondary controllers)
-
-Required properties:
-- compatible: Should be "nxp,lpc3220-mic"
-- interrupt-controller: Identifies the node as an interrupt controller.
-- interrupt-parent: Empty for the interrupt controller itself
-- #interrupt-cells: The number of cells to define the interrupts. Should be 2.
-  The first cell is the IRQ number
-  The second cell is used to specify mode:
-      1 = low-to-high edge triggered
-      2 = high-to-low edge triggered
-      4 = active high level-sensitive
-      8 = active low level-sensitive
-      Default for internal sources should be set to 4 (active high).
-- reg: Should contain MIC registers location and length
-
-Examples:
-       /*
-        * MIC
-        */
-       mic: interrupt-controller@40008000 {
-               compatible = "nxp,lpc3220-mic";
-               interrupt-controller;
-               interrupt-parent;
-               #interrupt-cells = <2>;
-               reg = <0x40008000 0xC000>;
-       };
-
-       /*
-        * ADC
-        */
-       adc@40048000 {
-               compatible = "nxp,lpc3220-adc";
-               reg = <0x40048000 0x1000>;
-               interrupt-parent = <&mic>;
-               interrupts = <39 4>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt
deleted file mode 100644 (file)
index afef6a8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-+Mediatek 65xx/67xx/81xx sysirq
-
-Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI
-interrupt.
-
-Required properties:
-- compatible: should be one of:
-       "mediatek,mt8173-sysirq"
-       "mediatek,mt8135-sysirq"
-       "mediatek,mt8127-sysirq"
-       "mediatek,mt6795-sysirq"
-       "mediatek,mt6592-sysirq"
-       "mediatek,mt6589-sysirq"
-       "mediatek,mt6582-sysirq"
-       "mediatek,mt6580-sysirq"
-       "mediatek,mt6577-sysirq"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Use the same format as specified by GIC in
-  Documentation/devicetree/bindings/arm/gic.txt
-- interrupt-parent: phandle of irq parent for sysirq. The parent must
-  use the same interrupt-cells format as GIC.
-- reg: Physical base address of the intpol registers and length of memory
-  mapped region.
-
-Example:
-       sysirq: interrupt-controller@10200100 {
-               compatible = "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq";
-               interrupt-controller;
-               #interrupt-cells = <3>;
-               interrupt-parent = <&gic>;
-               reg = <0 0x10200100 0 0x1c>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
deleted file mode 100644 (file)
index 8b53273..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-* Marvell MMP Interrupt controller
-
-Required properties:
-- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
-  "mrvl,mmp2-mux-intc"
-- reg : Address and length of the register set of the interrupt controller.
-  If the interrupt controller is intc, address and length means the range
-  of the whold interrupt controller. If the interrupt controller is mux-intc,
-  address and length means one register. Since address of mux-intc is in the
-  range of intc. mux-intc is secondary interrupt controller.
-- reg-names : Name of the register set of the interrupt controller. It's
-  only required in mux-intc interrupt controller.
-- interrupts : Should be the port interrupt shared by mux interrupts. It's
-  only required in mux-intc interrupt controller.
-- interrupt-controller : Identifies the node as an interrupt controller.
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source.
-- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt
-  controller.
-- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
-  detection first.
-
-Example:
-       intc: interrupt-controller@d4282000 {
-               compatible = "mrvl,mmp2-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               reg = <0xd4282000 0x1000>;
-               mrvl,intc-nr-irqs = <64>;
-       };
-
-       intcmux4@d4282150 {
-               compatible = "mrvl,mmp2-mux-intc";
-               interrupts = <4>;
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               reg = <0x150 0x4>, <0x168 0x4>;
-               reg-names = "mux status", "mux mask";
-               mrvl,intc-nr-irqs = <2>;
-       };
-
-* Marvell Orion Interrupt controller
-
-Required properties
-- compatible :  Should be "marvell,orion-intc".
-- #interrupt-cells: Specifies the number of cells needed to encode an
-  interrupt source. Supported value is <1>.
-- interrupt-controller : Declare this node to be an interrupt controller.
-- reg : Interrupt mask address. A list of 4 byte ranges, one per controller.
-        One entry in the list represents 32 interrupts.
-
-Example:
-
-       intc: interrupt-controller {
-               compatible = "marvell,orion-intc", "marvell,intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-                reg = <0xfed20204 0x04>,
-                     <0xfed20214 0x04>;
-        };
diff --git a/Documentation/devicetree/bindings/arm/omap/intc.txt b/Documentation/devicetree/bindings/arm/omap/intc.txt
deleted file mode 100644 (file)
index f2583e6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-* OMAP Interrupt Controller
-
-OMAP2/3 are using a TI interrupt controller that can support several
-configurable number of interrupts.
-
-Main node required properties:
-
-- compatible : should be:
-       "ti,omap2-intc"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The type shall be a <u32> and the value shall be 1.
-
-  The cell contains the interrupt number in the range [0-128].
-- ti,intc-size: Number of interrupts handled by the interrupt controller.
-- reg: physical base address and size of the intc registers map.
-
-Example:
-
-       intc: interrupt-controller@1 {
-               compatible = "ti,omap2-intc";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               ti,intc-size = <96>;
-               reg = <0x48200000 0x1000>;
-       };
-
diff --git a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
deleted file mode 100644 (file)
index 9e5f734..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-* Samsung Exynos Interrupt Combiner Controller
-
-Samsung's Exynos4 architecture includes a interrupt combiner controller which
-can combine interrupt sources as a group and provide a single interrupt request
-for the group. The interrupt request from each group are connected to a parent
-interrupt controller, such as GIC in case of Exynos4210.
-
-The interrupt combiner controller consists of multiple combiners. Up to eight
-interrupt sources can be connected to a combiner. The combiner outputs one
-combined interrupt for its eight interrupt sources. The combined interrupt
-is usually connected to a parent interrupt controller.
-
-A single node in the device tree is used to describe the interrupt combiner
-controller module (which includes multiple combiners). A combiner in the
-interrupt controller module shares config/control registers with other
-combiners. For example, a 32-bit interrupt enable/disable config register
-can accommodate up to 4 interrupt combiners (with each combiner supporting
-up to 8 interrupt sources).
-
-Required properties:
-- compatible: should be "samsung,exynos4210-combiner".
-- interrupt-controller: Identifies the node as an interrupt controller.
-- #interrupt-cells: should be <2>. The meaning of the cells are
-       * First Cell: Combiner Group Number.
-       * Second Cell: Interrupt number within the group.
-- reg: Base address and size of interrupt combiner registers.
-- interrupts: The list of interrupts generated by the combiners which are then
-    connected to a parent interrupt controller. The format of the interrupt
-    specifier depends in the interrupt parent controller.
-
-Optional properties:
-- samsung,combiner-nr: The number of interrupt combiners supported. If this
-  property is not specified, the default number of combiners is assumed
-  to be 16.
-- interrupt-parent: pHandle of the parent interrupt controller, if not
-  inherited from the parent node.
-
-
-Example:
-
-       The following is a an example from the Exynos4210 SoC dtsi file.
-
-       combiner:interrupt-controller@10440000 {
-               compatible = "samsung,exynos4210-combiner";
-               interrupt-controller;
-               #interrupt-cells = <2>;
-               reg = <0x10440000 0x1000>;
-               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
-                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
-                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
-                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/spear/shirq.txt b/Documentation/devicetree/bindings/arm/spear/shirq.txt
deleted file mode 100644 (file)
index 715a013..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-* SPEAr Shared IRQ layer (shirq)
-
-SPEAr3xx architecture includes shared/multiplexed irqs for certain set
-of devices. The multiplexor provides a single interrupt to parent
-interrupt controller (VIC) on behalf of a group of devices.
-
-There can be multiple groups available on SPEAr3xx variants but not
-exceeding 4. The number of devices in a group can differ, further they
-may share same set of status/mask registers spanning across different
-bit masks. Also in some cases the group may not have enable or other
-registers. This makes software little complex.
-
-A single node in the device tree is used to describe the shared
-interrupt multiplexor (one node for all groups). A group in the
-interrupt controller shares config/control registers with other groups.
-For example, a 32-bit interrupt enable/disable config register can
-accommodate up to 4 interrupt groups.
-
-Required properties:
-  - compatible: should be, either of
-     - "st,spear300-shirq"
-     - "st,spear310-shirq"
-     - "st,spear320-shirq"
-  - interrupt-controller: Identifies the node as an interrupt controller.
-  - #interrupt-cells: should be <1> which basically contains the offset
-    (starting from 0) of interrupts for all the groups.
-  - reg: Base address and size of shirq registers.
-  - interrupts: The list of interrupts generated by the groups which are
-    then connected to a parent interrupt controller. Each group is
-    associated with one of the interrupts, hence number of interrupts (to
-    parent) is equal to number of groups. The format of the interrupt
-    specifier depends in the interrupt parent controller.
-
-  Optional properties:
-  - interrupt-parent: pHandle of the parent interrupt controller, if not
-    inherited from the parent node.
-
-Example:
-
-The following is an example from the SPEAr320 SoC dtsi file.
-
-shirq: interrupt-controller@0xb3000000 {
-       compatible = "st,spear320-shirq";
-       reg = <0xb3000000 0x1000>;
-       interrupts = <28 29 30 1>;
-       #interrupt-cells = <1>;
-       interrupt-controller;
-};
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,nvec.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,nvec.txt
new file mode 100644 (file)
index 0000000..5ae601e
--- /dev/null
@@ -0,0 +1,21 @@
+NVIDIA compliant embedded controller
+
+Required properties:
+- compatible : should be "nvidia,nvec".
+- reg : the iomem of the i2c slave controller
+- interrupts : the interrupt line of the i2c slave controller
+- clock-frequency : the frequency of the i2c bus
+- gpios : the gpio used for ec request
+- slave-addr: the i2c address of the slave controller
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  Tegra20/Tegra30:
+  - div-clk
+  - fast-clk
+  Tegra114:
+  - div-clk
+- resets : Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names : Must include the following entries:
+  - i2c
diff --git a/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt b/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt
deleted file mode 100644 (file)
index c9cf605..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-* ARM Versatile FPGA interrupt controller
-
-One or more FPGA IRQ controllers can be synthesized in an ARM reference board
-such as the Integrator or Versatile family. The output of these different
-controllers are OR:ed together and fed to the CPU tile's IRQ input. Each
-instance can handle up to 32 interrupts.
-
-Required properties:
-- compatible: "arm,versatile-fpga-irq"
-- interrupt-controller: Identifies the node as an interrupt controller
-- #interrupt-cells: The number of cells to define the interrupts.  Must be 1
-  as the FPGA IRQ controller has no configuration options for interrupt
-  sources.  The cell is a u32 and defines the interrupt number.
-- reg: The register bank for the FPGA interrupt controller.
-- clear-mask: a u32 number representing the mask written to clear all IRQs
-  on the controller at boot for example.
-- valid-mask: a u32 number representing a bit mask determining which of
-  the interrupts are valid. Unconnected/unused lines are set to 0, and
-  the system till not make it possible for devices to request these
-  interrupts.
-
-Example:
-
-pic: pic@14000000 {
-        compatible = "arm,versatile-fpga-irq";
-        #interrupt-cells = <1>;
-        interrupt-controller;
-        reg = <0x14000000 0x100>;
-        clear-mask = <0xffffffff>;
-        valid-mask = <0x003fffff>;
-};
-
-Optional properties:
-- interrupts: if the FPGA IRQ controller is cascaded, i.e. if its IRQ
-  output is simply connected to the input of another IRQ controller,
-  then the parent IRQ shall be specified in this property.
diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
deleted file mode 100644 (file)
index dd52721..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-* ARM Vectored Interrupt Controller
-
-One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
-system for interrupt routing.  For multiple controllers they can either be
-nested or have the outputs wire-OR'd together.
-
-Required properties:
-
-- compatible : should be one of
-       "arm,pl190-vic"
-       "arm,pl192-vic"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
-  the VIC has no configuration options for interrupt sources.  The cell is a u32
-  and defines the interrupt number.
-- reg : The register bank for the VIC.
-
-Optional properties:
-
-- interrupts : Interrupt source for parent controllers if the VIC is nested.
-- valid-mask : A one cell big bit mask of valid interrupt sources. Each bit
-  represents single interrupt source, starting from source 0 at LSb and ending
-  at source 31 at MSb. A bit that is set means that the source is wired and
-  clear means otherwise. If unspecified, defaults to all valid.
-- valid-wakeup-mask : A one cell big bit mask of interrupt sources that can be
-  configured as wake up source for the system. Order of bits is the same as for
-  valid-mask property. A set bit means that this interrupt source can be
-  configured as a wake up source for the system. If unspecied, defaults to all
-  interrupt sources configurable as wake up sources.
-
-Example:
-
-       vic0: interrupt-controller@60000 {
-               compatible = "arm,pl192-vic";
-               interrupt-controller;
-               #interrupt-cells = <1>;
-               reg = <0x60000 0x1000>;
-
-               valid-mask = <0xffffff7f>;
-               valid-wakeup-mask = <0x0000ff7f>;
-       };
diff --git a/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt
deleted file mode 100644 (file)
index 0a4ce10..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-VIA/Wondermedia VT8500 Interrupt Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-intc"
-- reg : Should contain 1 register ranges(address and length)
-- #interrupt-cells : should be <1>
-
-Example:
-
-       intc: interrupt-controller@d8140000 {
-               compatible = "via,vt8500-intc";
-               interrupt-controller;
-               reg = <0xd8140000 0x10000>;
-               #interrupt-cells = <1>;
-       };
diff --git a/Documentation/devicetree/bindings/c6x/interrupt.txt b/Documentation/devicetree/bindings/c6x/interrupt.txt
deleted file mode 100644 (file)
index 42bb796..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-C6X Interrupt Chips
--------------------
-
-* C64X+ Core Interrupt Controller
-
-  The core interrupt controller provides 16 prioritized interrupts to the
-  C64X+ core. Priority 0 and 1 are used for reset and NMI respectively.
-  Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt
-  sources coming from outside the core.
-
-  Required properties:
-  --------------------
-  - compatible: Should be "ti,c64x+core-pic";
-  - #interrupt-cells: <1>
-
-  Interrupt Specifier Definition
-  ------------------------------
-  Single cell specifying the core interrupt priority level (4-15) where
-  4 is highest priority and 15 is lowest priority.
-
-  Example
-  -------
-  core_pic: interrupt-controller@0 {
-       interrupt-controller;
-       #interrupt-cells = <1>;
-       compatible = "ti,c64x+core-pic";
-  };
-
-
-
-* C64x+ Megamodule Interrupt Controller
-
-  The megamodule PIC consists of four interrupt mupliplexers each of which
-  combine up to 32 interrupt inputs into a single interrupt output which
-  may be cascaded into the core interrupt controller. The megamodule PIC
-  has a total of 12 outputs cascading into the core interrupt controller.
-  One for each core interrupt priority level. In addition to the combined
-  interrupt sources, individual megamodule interrupts may be cascaded to
-  the core interrupt controller. When an individual interrupt is cascaded,
-  it is no longer handled through a megamodule interrupt combiner and is
-  considered to have the core interrupt controller as the parent.
-
-  Required properties:
-  --------------------
-  - compatible: "ti,c64x+megamod-pic"
-  - interrupt-controller
-  - #interrupt-cells: <1>
-  - reg: base address and size of register area
-  - interrupt-parent: must be core interrupt controller
-  - interrupts: This should have four cells; one for each interrupt combiner.
-                The cells contain the core priority interrupt to which the
-                corresponding combiner output is wired.
-
-  Optional properties:
-  --------------------
-  - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core
-                             priority interrupts. The first cell corresponds to
-                             core priority 4 and the last cell corresponds to
-                             core priority 15. The value of each cell is the
-                             megamodule interrupt source which is MUXed to
-                             the core interrupt corresponding to the cell
-                             position. Allowed values are 4 - 127. Mapping for
-                             interrupts 0 - 3 (combined interrupt sources) are
-                             ignored.
-
-  Interrupt Specifier Definition
-  ------------------------------
-  Single cell specifying the megamodule interrupt source (4-127). Note that
-  interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will
-  use the core interrupt controller as their parent and the specifier will
-  be the core priority level, not the megamodule interrupt number.
-
-  Examples
-  --------
-  megamod_pic: interrupt-controller@1800000 {
-       compatible = "ti,c64x+megamod-pic";
-       interrupt-controller;
-       #interrupt-cells = <1>;
-       reg = <0x1800000 0x1000>;
-       interrupt-parent = <&core_pic>;
-       interrupts = < 12 13 14 15 >;
-  };
-
-  This is a minimal example where all individual interrupts go through a
-  combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped
-  to interrupt 13, etc.
-
-
-  megamod_pic: interrupt-controller@1800000 {
-       compatible = "ti,c64x+megamod-pic";
-       interrupt-controller;
-       #interrupt-cells = <1>;
-       reg = <0x1800000 0x1000>;
-       interrupt-parent = <&core_pic>;
-       interrupts = < 12 13 14 15 >;
-       ti,c64x+megamod-pic-mux = <  0  0  0  0
-                                    32  0  0  0
-                                     0  0  0  0 >;
-  };
-
-  This the same as the first example except that megamodule interrupt 32 is
-  mapped directly to core priority interrupt 8. The node using this interrupt
-  must set the core controller as its interrupt parent and use 8 in the
-  interrupt specifier value.
diff --git a/Documentation/devicetree/bindings/cris/interrupts.txt b/Documentation/devicetree/bindings/cris/interrupts.txt
deleted file mode 100644 (file)
index e8b123b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-* CRISv32 Interrupt Controller
-
-Interrupt controller for the CRISv32 SoCs.
-
-Main node required properties:
-
-- compatible : should be:
-       "axis,crisv32-intc"
-- interrupt-controller : Identifies the node as an interrupt controller
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The type shall be a <u32> and the value shall be 1.
-- reg: physical base address and size of the intc registers map.
-
-Example:
-
-       intc: interrupt-controller {
-               compatible = "axis,crisv32-intc";
-               reg = <0xb001c000 0x1000>;
-               interrupt-controller;
-               #interrupt-cells = <1>;
-       };
-
-
index 6831d025ec24403668bbe0644d76e3c8c8c2b636..adeca34c5a33b4ddade769ba9e7dd79e184c9a11 100644 (file)
@@ -441,7 +441,7 @@ EXAMPLE:
                regmap = <&snvs>;
                interrupts = <0 4 0x4>
                linux,keycode = <116>; /* KEY_POWER */
-               wakeup;
+               wakeup-source;
        };
 
 =====================================================================
@@ -530,7 +530,7 @@ FULL EXAMPLE
                        regmap = <&sec_mon>;
                        interrupts = <0 4 0x4>;
                        linux,keycode = <116>; /* KEY_POWER */
-                       wakeup;
+                       wakeup-source;
                };
        };
 
diff --git a/Documentation/devicetree/bindings/display/arm,pl11x.txt b/Documentation/devicetree/bindings/display/arm,pl11x.txt
new file mode 100644 (file)
index 0000000..3e3039a
--- /dev/null
@@ -0,0 +1,109 @@
+* ARM PrimeCell Color LCD Controller PL110/PL111
+
+See also Documentation/devicetree/bindings/arm/primecell.txt
+
+Required properties:
+
+- compatible: must be one of:
+       "arm,pl110", "arm,primecell"
+       "arm,pl111", "arm,primecell"
+
+- reg: base address and size of the control registers block
+
+- interrupt-names: either the single entry "combined" representing a
+       combined interrupt output (CLCDINTR), or the four entries
+       "mbe", "vcomp", "lnbu", "fuf" representing the individual
+       CLCDMBEINTR, CLCDVCOMPINTR, CLCDLNBUINTR, CLCDFUFINTR interrupts
+
+- interrupts: contains an interrupt specifier for each entry in
+       interrupt-names
+
+- clock-names: should contain "clcdclk" and "apb_pclk"
+
+- clocks: contains phandle and clock specifier pairs for the entries
+       in the clock-names property. See
+       Documentation/devicetree/binding/clock/clock-bindings.txt
+
+Optional properties:
+
+- memory-region: phandle to a node describing memory (see
+       Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
+       to be used for the framebuffer; if not present, the framebuffer
+       may be located anywhere in the memory
+
+- max-memory-bandwidth: maximum bandwidth in bytes per second that the
+       cell's memory interface can handle; if not present, the memory
+       interface is fast enough to handle all possible video modes
+
+Required sub-nodes:
+
+- port: describes LCD panel signals, following the common binding
+       for video transmitter interfaces; see
+       Documentation/devicetree/bindings/media/video-interfaces.txt;
+       when it is a TFT panel, the port's endpoint must define the
+       following property:
+
+       - arm,pl11x,tft-r0g0b0-pads: an array of three 32-bit values,
+               defining the way CLD pads are wired up; first value
+               contains index of the "CLD" external pin (pad) used
+               as R0 (first bit of the red component), second value
+               index of the pad used as G0, third value index of the
+               pad used as B0, see also "LCD panel signal multiplexing
+               details" paragraphs in the PL110/PL111 Technical
+               Reference Manuals; this implicitly defines available
+               color modes, for example:
+               - PL111 TFT 4:4:4 panel:
+                       arm,pl11x,tft-r0g0b0-pads = <4 15 20>;
+               - PL110 TFT (1:)5:5:5 panel:
+                       arm,pl11x,tft-r0g0b0-pads = <1 7 13>;
+               - PL111 TFT (1:)5:5:5 panel:
+                       arm,pl11x,tft-r0g0b0-pads = <3 11 19>;
+               - PL111 TFT 5:6:5 panel:
+                       arm,pl11x,tft-r0g0b0-pads = <3 10 19>;
+               - PL110 and PL111 TFT 8:8:8 panel:
+                       arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+               - PL110 and PL111 TFT 8:8:8 panel, R & B components swapped:
+                       arm,pl11x,tft-r0g0b0-pads = <16 8 0>;
+
+
+Example:
+
+       clcd@10020000 {
+               compatible = "arm,pl111", "arm,primecell";
+               reg = <0x10020000 0x1000>;
+               interrupt-names = "combined";
+               interrupts = <0 44 4>;
+               clocks = <&oscclk1>, <&oscclk2>;
+               clock-names = "clcdclk", "apb_pclk";
+               max-memory-bandwidth = <94371840>; /* Bps, 1024x768@60 16bpp */
+
+               port {
+                       clcd_pads: endpoint {
+                               remote-endpoint = <&clcd_panel>;
+                               arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+                       };
+               };
+
+       };
+
+       panel {
+               compatible = "panel-dpi";
+
+               port {
+                       clcd_panel: endpoint {
+                               remote-endpoint = <&clcd_pads>;
+                       };
+               };
+
+               panel-timing {
+                       clock-frequency = <25175000>;
+                       hactive = <640>;
+                       hback-porch = <40>;
+                       hfront-porch = <24>;
+                       hsync-len = <96>;
+                       vactive = <480>;
+                       vback-porch = <32>;
+                       vfront-porch = <11>;
+                       vsync-len = <2>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/armada/marvell,dove-lcd.txt b/Documentation/devicetree/bindings/display/armada/marvell,dove-lcd.txt
new file mode 100644 (file)
index 0000000..46525ea
--- /dev/null
@@ -0,0 +1,30 @@
+Device Tree bindings for Armada DRM CRTC driver
+
+Required properties:
+ - compatible: value should be "marvell,dove-lcd".
+ - reg: base address and size of the LCD controller
+ - interrupts: single interrupt number for the LCD controller
+ - port: video output port with endpoints, as described by graph.txt
+
+Optional properties:
+
+ - clocks: as described by clock-bindings.txt
+ - clock-names: as described by clock-bindings.txt
+       "axiclk" - axi bus clock for pixel clock
+       "plldivider" - pll divider clock for pixel clock
+       "ext_ref_clk0" - external clock 0 for pixel clock
+       "ext_ref_clk1" - external clock 1 for pixel clock
+
+Note: all clocks are optional but at least one must be specified.
+Further clocks may be added in the future according to requirements of
+different SoCs.
+
+Example:
+
+       lcd0: lcd-controller@820000 {
+               compatible = "marvell,dove-lcd";
+               reg = <0x820000 0x1000>;
+               interrupts = <47>;
+               clocks = <&si5351 0>;
+               clock-names = "ext_ref_clk_1";
+       };
diff --git a/Documentation/devicetree/bindings/display/atmel,lcdc.txt b/Documentation/devicetree/bindings/display/atmel,lcdc.txt
new file mode 100644 (file)
index 0000000..ecb8da0
--- /dev/null
@@ -0,0 +1,89 @@
+Atmel LCDC Framebuffer
+-----------------------------------------------------
+
+Required properties:
+- compatible :
+       "atmel,at91sam9261-lcdc" , 
+       "atmel,at91sam9263-lcdc" ,
+       "atmel,at91sam9g10-lcdc" ,
+       "atmel,at91sam9g45-lcdc" ,
+       "atmel,at91sam9g45es-lcdc" ,
+       "atmel,at91sam9rl-lcdc" ,
+       "atmel,at32ap-lcdc"
+- reg : Should contain 1 register ranges(address and length).
+       Can contain an additional register range(address and length)
+       for fixed framebuffer memory. Useful for dedicated memories.
+- interrupts : framebuffer controller interrupt
+- display: a phandle pointing to the display node
+
+Required nodes:
+- display: a display node is required to initialize the lcd panel
+       This should be in the board dts.
+- default-mode: a videomode within the display with timing parameters
+       as specified below.
+
+Optional properties:
+- lcd-supply: Regulator for LCD supply voltage.
+
+Example:
+
+       fb0: fb@0x00500000 {
+               compatible = "atmel,at91sam9g45-lcdc";
+               reg = <0x00500000 0x1000>;
+               interrupts = <23 3 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_fb>;
+               display = <&display0>;
+               status = "okay";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+       };
+
+Example for fixed framebuffer memory:
+
+       fb0: fb@0x00500000 {
+               compatible = "atmel,at91sam9263-lcdc";
+               reg = <0x00700000 0x1000 0x70000000 0x200000>;
+               [...]
+       };
+
+Atmel LCDC Display
+-----------------------------------------------------
+Required properties (as per of_videomode_helper):
+
+ - atmel,dmacon: dma controller configuration
+ - atmel,lcdcon2: lcd controller configuration
+ - atmel,guard-time: lcd guard time (Delay in frame periods)
+ - bits-per-pixel: lcd panel bit-depth.
+
+Optional properties (as per of_videomode_helper):
+ - atmel,lcdcon-backlight: enable backlight
+ - atmel,lcdcon-backlight-inverted: invert backlight PWM polarity
+ - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"
+ - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
+
+Example:
+       display0: display {
+               bits-per-pixel = <32>;
+               atmel,lcdcon-backlight;
+               atmel,dmacon = <0x1>;
+               atmel,lcdcon2 = <0x80008002>;
+               atmel,guard-time = <9>;
+               atmel,lcd-wiring-mode = <1>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: timing0 {
+                               clock-frequency = <9000000>;
+                               hactive = <480>;
+                               vactive = <272>;
+                               hback-porch = <1>;
+                               hfront-porch = <1>;
+                               vback-porch = <40>;
+                               vfront-porch = <1>;
+                               hsync-len = <45>;
+                               vsync-len = <1>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
new file mode 100644 (file)
index 0000000..ebc1a91
--- /dev/null
@@ -0,0 +1,53 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
+
+The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
+See ../mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be "atmel,hlcdc-display-controller"
+ - pinctrl-names: the pin control state names. Should contain "default".
+ - pinctrl-0: should contain the default pinctrl states.
+ - #address-cells: should be set to 1.
+ - #size-cells: should be set to 0.
+
+Required children nodes:
+ Children nodes are encoding available output ports and their connections
+ to external devices using the OF graph reprensentation (see ../graph.txt).
+ At least one port node is required.
+
+Example:
+
+       hlcdc: hlcdc@f0030000 {
+               compatible = "atmel,sama5d3-hlcdc";
+               reg = <0xf0030000 0x2000>;
+               interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+               clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+               clock-names = "periph_clk","sys_clk", "slow_clk";
+               status = "disabled";
+
+               hlcdc-display-controller {
+                       compatible = "atmel,hlcdc-display-controller";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0>;
+
+                               hlcdc_panel_output: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&panel_input>;
+                               };
+                       };
+               };
+
+               hlcdc_pwm: hlcdc-pwm {
+                       compatible = "atmel,hlcdc-pwm";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_lcd_pwm>;
+                       #pwm-cells = <3>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7123.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7123.txt
new file mode 100644 (file)
index 0000000..a6b2b2b
--- /dev/null
@@ -0,0 +1,50 @@
+Analog Device ADV7123 Video DAC
+-------------------------------
+
+The ADV7123 is a digital-to-analog converter that outputs VGA signals from a
+parallel video input.
+
+Required properties:
+
+- compatible: Should be "adi,adv7123"
+
+Optional properties:
+
+- psave-gpios: Power save control GPIO
+
+Required nodes:
+
+The ADV7123 has two video ports. Their connections are modeled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for DPI input
+- Video port 1 for VGA output
+
+
+Example
+-------
+
+       adv7123: encoder@0 {
+               compatible = "adi,adv7123";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               adv7123_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               adv7123_out: endpoint@0 {
+                                       remote-endpoint = <&vga_connector_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
new file mode 100644 (file)
index 0000000..96c25ee
--- /dev/null
@@ -0,0 +1,88 @@
+Analog Device ADV7511(W)/13 HDMI Encoders
+-----------------------------------------
+
+The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
+S/PDIF, CEC and HDCP.
+
+Required properties:
+
+- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- reg: I2C slave address
+
+The ADV7511 supports a large number of input data formats that differ by their
+color depth, color format, clock mode, bit justification and random
+arrangement of components on the data bus. The combination of the following
+properties describe the input and map directly to the video input tables of the
+ADV7511 datasheet that document all the supported combinations.
+
+- adi,input-depth: Number of bits per color component at the input (8, 10 or
+  12).
+- adi,input-colorspace: The input color space, one of "rgb", "yuv422" or
+  "yuv444".
+- adi,input-clock: The input clock type, one of "1x" (one clock cycle per
+  pixel), "2x" (two clock cycles per pixel), "ddr" (one clock cycle per pixel,
+  data driven on both edges).
+
+The following input format properties are required except in "rgb 1x" and
+"yuv444 1x" modes, in which case they must not be specified.
+
+- adi,input-style: The input components arrangement variant (1, 2 or 3), as
+  listed in the input format tables in the datasheet.
+- adi,input-justification: The input bit justification ("left", "evenly",
+  "right").
+
+Optional properties:
+
+- interrupts: Specifier for the ADV7511 interrupt
+- pd-gpios: Specifier for the GPIO connected to the power down signal
+
+- adi,clock-delay: Video data clock delay relative to the pixel clock, in ps
+  (-1200 ps .. 1600 ps). Defaults to no delay.
+- adi,embedded-sync: The input uses synchronization signals embedded in the
+  data stream (similar to BT.656). Defaults to separate H/V synchronization
+  signals.
+
+Required nodes:
+
+The ADV7511 has two video ports. Their connections are modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for the RGB or YUV input
+- Video port 1 for the HDMI output
+
+
+Example
+-------
+
+       adv7511w: hdmi@39 {
+               compatible = "adi,adv7511w";
+               reg = <39>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
+
+               adi,input-depth = <8>;
+               adi,input-colorspace = "rgb";
+               adi,input-clock = "1x";
+               adi,input-style = <1>;
+               adi,input-justification = "evenly";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               adv7511w_in: endpoint {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               adv7511_out: endpoint {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt
new file mode 100644 (file)
index 0000000..dc1452f
--- /dev/null
@@ -0,0 +1,50 @@
+DesignWare HDMI bridge bindings
+
+Required properties:
+- compatible: platform specific such as:
+   * "snps,dw-hdmi-tx"
+   * "fsl,imx6q-hdmi"
+   * "fsl,imx6dl-hdmi"
+   * "rockchip,rk3288-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The HDMI interrupt number
+- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
+  as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
+  the clocks are soc specific, the clock-names should be "iahb", "isfr"
+-port@[X]: SoC specific port nodes with endpoint definitions as defined
+   in Documentation/devicetree/bindings/media/video-interfaces.txt,
+   please refer to the SoC specific binding document:
+    * Documentation/devicetree/bindings/display/imx/hdmi.txt
+    * Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+
+Example:
+       hdmi: hdmi@0120000 {
+               compatible = "fsl,imx6q-hdmi";
+               reg = <0x00120000 0x9000>;
+               interrupts = <0 115 0x04>;
+               gpr = <&gpr>;
+               clocks = <&clks 123>, <&clks 124>;
+               clock-names = "iahb", "isfr";
+               ddc-i2c-bus = <&i2c2>;
+
+               port@0 {
+                       reg = <0>;
+
+                       hdmi_mux_0: endpoint {
+                               remote-endpoint = <&ipu1_di0_hdmi>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       hdmi_mux_1: endpoint {
+                               remote-endpoint = <&ipu1_di1_hdmi>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/ps8622.txt b/Documentation/devicetree/bindings/display/bridge/ps8622.txt
new file mode 100644 (file)
index 0000000..c989c38
--- /dev/null
@@ -0,0 +1,31 @@
+ps8622-bridge bindings
+
+Required properties:
+       - compatible: "parade,ps8622" or "parade,ps8625"
+       - reg: first i2c address of the bridge
+       - sleep-gpios: OF device-tree gpio specification for PD_ pin.
+       - reset-gpios: OF device-tree gpio specification for RST_ pin.
+
+Optional properties:
+       - lane-count: number of DP lanes to use
+       - use-external-pwm: backlight will be controlled by an external PWM
+       - video interfaces: Device node can contain video interface port
+                           nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+       lvds-bridge@48 {
+               compatible = "parade,ps8622";
+               reg = <0x48>;
+               sleep-gpios = <&gpc3 6 1 0 0>;
+               reset-gpios = <&gpc3 1 1 0 0>;
+               lane-count = <1>;
+               ports {
+                       port@0 {
+                               bridge_out: endpoint {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/ptn3460.txt b/Documentation/devicetree/bindings/display/bridge/ptn3460.txt
new file mode 100644 (file)
index 0000000..361971b
--- /dev/null
@@ -0,0 +1,39 @@
+ptn3460 bridge bindings
+
+Required properties:
+       - compatible: "nxp,ptn3460"
+       - reg: i2c address of the bridge
+       - powerdown-gpio: OF device-tree gpio specification  for PD_N pin.
+       - reset-gpio: OF device-tree gpio specification for RST_N pin.
+       - edid-emulation: The EDID emulation entry to use
+               +-------+------------+------------------+
+               | Value | Resolution | Description      |
+               |   0   |  1024x768  | NXP Generic      |
+               |   1   |  1920x1080 | NXP Generic      |
+               |   2   |  1920x1080 | NXP Generic      |
+               |   3   |  1600x900  | Samsung LTM200KT |
+               |   4   |  1920x1080 | Samsung LTM230HT |
+               |   5   |  1366x768  | NXP Generic      |
+               |   6   |  1600x900  | ChiMei M215HGE   |
+               +-------+------------+------------------+
+
+       - video interfaces: Device node can contain video interface port
+                           nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+       lvds-bridge@20 {
+               compatible = "nxp,ptn3460";
+               reg = <0x20>;
+               powerdown-gpio = <&gpy2 5 1 0 0>;
+               reset-gpio = <&gpx1 5 1 0 0>;
+               edid-emulation = <5>;
+               ports {
+                       port@0 {
+                               bridge_out: endpoint {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/tda998x.txt b/Documentation/devicetree/bindings/display/bridge/tda998x.txt
new file mode 100644 (file)
index 0000000..e9e4bce
--- /dev/null
@@ -0,0 +1,29 @@
+Device-Tree bindings for the NXP TDA998x HDMI transmitter
+
+Required properties;
+  - compatible: must be "nxp,tda998x"
+
+  - reg: I2C address
+
+Optional properties:
+  - interrupts: interrupt number and trigger type
+       default: polling
+
+  - pinctrl-0: pin control group to be used for
+       screen plug/unplug interrupt.
+
+  - pinctrl-names: must contain a "default" entry.
+
+  - video-ports: 24 bits value which defines how the video controller
+       output is wired to the TDA998x input - default: <0x230145>
+
+Example:
+
+       tda998x: hdmi-encoder {
+               compatible = "nxp,tda998x";
+               reg = <0x70>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <27 2>;            /* falling edge */
+               pinctrl-0 = <&pmx_camera>;
+               pinctrl-names = "default";
+       };
diff --git a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt b/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt
new file mode 100644 (file)
index 0000000..527e236
--- /dev/null
@@ -0,0 +1,50 @@
+THine Electronics THC63LVDM83D LVDS serializer
+----------------------------------------------
+
+The THC63LVDM83D is an LVDS serializer designed to support pixel data
+transmission between a host and a flat panel.
+
+Required properties:
+
+- compatible: Should be "thine,thc63lvdm83d"
+
+Optional properties:
+
+- pwdn-gpios: Power down control GPIO
+
+Required nodes:
+
+The THC63LVDM83D has two video ports. Their connections are modeled using the
+OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for CMOS/TTL input
+- Video port 1 for LVDS output
+
+
+Example
+-------
+
+       lvds_enc: encoder@0 {
+               compatible = "thine,thc63lvdm83d";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               lvds_enc_in: endpoint@0 {
+                                       remote-endpoint = <&rgb_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               lvds_enc_out: endpoint@0 {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/cirrus,clps711x-fb.txt b/Documentation/devicetree/bindings/display/cirrus,clps711x-fb.txt
new file mode 100644 (file)
index 0000000..d685be8
--- /dev/null
@@ -0,0 +1,47 @@
+* Currus Logic CLPS711X Framebuffer
+
+Required properties:
+- compatible: Shall contain "cirrus,clps711x-fb".
+- reg       : Physical base address and length of the controller's registers +
+              location and size of the framebuffer memory.
+- clocks    : phandle + clock specifier pair of the FB reference clock.
+- display   : phandle to a display node as described in
+              Documentation/devicetree/bindings/display/display-timing.txt.
+              Additionally, the display node has to define properties:
+  - bits-per-pixel: Bits per pixel.
+  - ac-prescale   : LCD AC bias frequency. This frequency is the required
+                    AC bias frequency for a given manufacturer's LCD plate.
+  - cmap-invert   : Invert the color levels (Optional).
+
+Optional properties:
+- lcd-supply: Regulator for LCD supply voltage.
+
+Example:
+       fb: fb@800002c0 {
+               compatible = "cirrus,ep7312-fb", "cirrus,clps711x-fb";
+               reg = <0x800002c0 0xd44>, <0x60000000 0xc000>;
+               clocks = <&clks 2>;
+               lcd-supply = <&reg5v0>;
+               display = <&display>;
+       };
+
+       display: display {
+               model = "320x240x4";
+               native-mode = <&timing0>;
+               bits-per-pixel = <4>;
+               ac-prescale = <17>;
+
+               display-timings {
+                       timing0: 320x240 {
+                               hactive = <320>;
+                               hback-porch = <0>;
+                               hfront-porch = <0>;
+                               hsync-len = <0>;
+                               vactive = <240>;
+                               vback-porch = <0>;
+                               vfront-porch = <0>;
+                               vsync-len = <0>;
+                               clock-frequency = <6500000>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
new file mode 100644 (file)
index 0000000..0c0970c
--- /dev/null
@@ -0,0 +1,25 @@
+Analog TV Connector
+===================
+
+Required properties:
+- compatible: "composite-video-connector" or "svideo-connector"
+
+Optional properties:
+- label: a symbolic name for the connector
+
+Required nodes:
+- Video port for TV input
+
+Example
+-------
+
+tv: connector {
+       compatible = "composite-video-connector";
+       label = "tv";
+
+       port {
+               tv_connector_in: endpoint {
+                       remote-endpoint = <&venc_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/connector/dvi-connector.txt b/Documentation/devicetree/bindings/display/connector/dvi-connector.txt
new file mode 100644 (file)
index 0000000..fc53f7c
--- /dev/null
@@ -0,0 +1,35 @@
+DVI Connector
+==============
+
+Required properties:
+- compatible: "dvi-connector"
+
+Optional properties:
+- label: a symbolic name for the connector
+- ddc-i2c-bus: phandle to the i2c bus that is connected to DVI DDC
+- analog: the connector has DVI analog pins
+- digital: the connector has DVI digital pins
+- dual-link: the connector has pins for DVI dual-link
+
+Required nodes:
+- Video port for DVI input
+
+Note: One (or both) of 'analog' or 'digital' must be set.
+
+Example
+-------
+
+dvi0: connector@0 {
+       compatible = "dvi-connector";
+       label = "dvi";
+
+       digital;
+
+       ddc-i2c-bus = <&i2c3>;
+
+       port {
+               dvi_connector_in: endpoint {
+                       remote-endpoint = <&tfp410_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt b/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt
new file mode 100644 (file)
index 0000000..acd5668
--- /dev/null
@@ -0,0 +1,29 @@
+HDMI Connector
+==============
+
+Required properties:
+- compatible: "hdmi-connector"
+- type: the HDMI connector type: "a", "b", "c", "d" or "e"
+
+Optional properties:
+- label: a symbolic name for the connector
+- hpd-gpios: HPD GPIO number
+
+Required nodes:
+- Video port for HDMI input
+
+Example
+-------
+
+hdmi0: connector@1 {
+       compatible = "hdmi-connector";
+       label = "hdmi";
+
+       type = "a";
+
+       port {
+               hdmi_connector_in: endpoint {
+                       remote-endpoint = <&tpd12s015_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/connector/vga-connector.txt b/Documentation/devicetree/bindings/display/connector/vga-connector.txt
new file mode 100644 (file)
index 0000000..c727f29
--- /dev/null
@@ -0,0 +1,36 @@
+VGA Connector
+=============
+
+Required properties:
+
+- compatible: "vga-connector"
+
+Optional properties:
+
+- label: a symbolic name for the connector corresponding to a hardware label
+- ddc-i2c-bus: phandle to the I2C bus that is connected to VGA DDC
+
+Required nodes:
+
+The VGA connector internal connections are modeled using the OF graph bindings
+specified in Documentation/devicetree/bindings/graph.txt.
+
+The VGA connector has a single port that must be connected to a video source
+port.
+
+
+Example
+-------
+
+vga0: connector@0 {
+       compatible = "vga-connector";
+       label = "vga";
+
+       ddc-i2c-bus = <&i2c3>;
+
+       port {
+               vga_connector_in: endpoint {
+                       remote-endpoint = <&adv7123_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos-mic.txt b/Documentation/devicetree/bindings/display/exynos/exynos-mic.txt
new file mode 100644 (file)
index 0000000..0fba2ee
--- /dev/null
@@ -0,0 +1,51 @@
+Device-Tree bindings for Samsung Exynos SoC mobile image compressor (MIC)
+
+MIC (mobile image compressor) resides between decon and mipi dsi. Mipi dsi is
+not capable to transfer high resoltuion frame data as decon can send. MIC
+solves this problem by compressing the frame data by 1/2 before it is
+transferred through mipi dsi. The compressed frame data must be uncompressed in
+the panel PCB.
+
+Required properties:
+- compatible: value should be "samsung,exynos5433-mic".
+- reg: physical base address and length of the MIC registers set and system
+       register of mic.
+- clocks: must include clock specifiers corresponding to entries in the
+         clock-names property.
+- clock-names: list of clock names sorted in the same order as the clocks
+              property. Must contain "pclk_mic0", "sclk_rgb_vclk_to_mic0".
+- samsung,disp-syscon: the reference node for syscon for DISP block.
+- ports: contains a port which is connected to decon node and dsi node.
+        address-cells and size-cells must 1 and 0, respectively.
+- port: contains an endpoint node which is connected to the endpoint in the
+       decon node or dsi node. The reg value must be 0 and 1 respectively.
+
+Example:
+SoC specific DT entry:
+mic: mic@13930000 {
+       compatible = "samsung,exynos5433-mic";
+       reg = <0x13930000 0x48>;
+       clocks = <&cmu_disp CLK_PCLK_MIC0>,
+              <&cmu_disp CLK_SCLK_RGB_VCLK_TO_MIC0>;
+       clock-names = "pclk_mic0", "sclk_rgb_vclk_to_mic0";
+       samsung,disp-syscon = <&syscon_disp>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       mic_to_decon: endpoint {
+                               remote-endpoint = <&decon_to_mic>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+                       mic_to_dsi: endpoint {
+                               remote-endpoint = <&dsi_to_mic>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt b/Documentation/devicetree/bindings/display/exynos/exynos5433-decon.txt
new file mode 100644 (file)
index 0000000..377afbf
--- /dev/null
@@ -0,0 +1,65 @@
+Device-Tree bindings for Samsung Exynos SoC display controller (DECON)
+
+DECON (Display and Enhancement Controller) is the Display Controller for the
+Exynos series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be "samsung,exynos5433-decon";
+- reg: physical base address and length of the DECON registers set.
+- interrupts: should contain a list of all DECON IP block interrupts in the
+             order: VSYNC, LCD_SYSTEM. The interrupt specifier format
+             depends on the interrupt controller used.
+- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys"
+                  in the same order as they were listed in the interrupts
+                  property.
+- clocks: must include clock specifiers corresponding to entries in the
+         clock-names property.
+- clock-names: list of clock names sorted in the same order as the clocks
+              property. Must contain "aclk_decon", "aclk_smmu_decon0x",
+              "aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk",
+              "sclk_decon_eclk"
+- ports: contains a port which is connected to mic node. address-cells and
+        size-cells must 1 and 0, respectively.
+- port: contains an endpoint node which is connected to the endpoint in the mic
+       node. The reg value muset be 0.
+- i80-if-timings: specify whether the panel which is connected to decon uses
+                 i80 lcd interface or mipi video interface. This node contains
+                 no timing information as that of fimd does. Because there is
+                 no register in decon to specify i80 interface timing value,
+                 it is not needed, but make it remain to use same kind of node
+                 in fimd and exynos7 decon.
+
+Example:
+SoC specific DT entry:
+decon: decon@13800000 {
+       compatible = "samsung,exynos5433-decon";
+       reg = <0x13800000 0x2104>;
+       clocks = <&cmu_disp CLK_ACLK_DECON>, <&cmu_disp CLK_ACLK_SMMU_DECON0X>,
+               <&cmu_disp CLK_ACLK_XIU_DECON0X>,
+               <&cmu_disp CLK_PCLK_SMMU_DECON0X>,
+               <&cmu_disp CLK_SCLK_DECON_VCLK>,
+               <&cmu_disp CLK_SCLK_DECON_ECLK>;
+       clock-names = "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x",
+               "pclk_smmu_decon0x", "sclk_decon_vclk", "sclk_decon_eclk";
+       interrupt-names = "vsync", "lcd_sys";
+       interrupts = <0 202 0>, <0 203 0>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       decon_to_mic: endpoint {
+                               remote-endpoint = <&mic_to_decon>;
+                       };
+               };
+       };
+};
+
+Board specific DT entry:
+&decon {
+       i80-if-timings {
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos7-decon.txt b/Documentation/devicetree/bindings/display/exynos/exynos7-decon.txt
new file mode 100644 (file)
index 0000000..3938caa
--- /dev/null
@@ -0,0 +1,68 @@
+Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON)
+
+DECON (Display and Enhancement Controller) is the Display Controller for the
+Exynos7 series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be "samsung,exynos7-decon";
+
+- reg: physical base address and length of the DECON registers set.
+
+- interrupt-parent: should be the phandle of the decon controller's
+               parent interrupt controller.
+
+- interrupts: should contain a list of all DECON IP block interrupts in the
+                order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
+                format depends on the interrupt controller used.
+
+- interrupt-names: should contain the interrupt names: "fifo", "vsync",
+       "lcd_sys", in the same order as they were listed in the interrupts
+        property.
+
+- pinctrl-0: pin control group to be used for this controller.
+
+- pinctrl-names: must contain a "default" entry.
+
+- clocks: must include clock specifiers corresponding to entries in the
+         clock-names property.
+
+- clock-names: list of clock names sorted in the same order as the clocks
+               property. Must contain "pclk_decon0", "aclk_decon0",
+              "decon0_eclk", "decon0_vclk".
+- i80-if-timings: timing configuration for lcd i80 interface support.
+
+Optional Properties:
+- samsung,power-domain: a phandle to DECON power domain node.
+- display-timings: timing settings for DECON, as described in document [1].
+               Can be used in case timings cannot be provided otherwise
+               or to override timings provided by the panel.
+
+[1]: Documentation/devicetree/bindings/display/display-timing.txt
+
+Example:
+
+SoC specific DT entry:
+
+       decon@13930000 {
+               compatible = "samsung,exynos7-decon";
+               interrupt-parent = <&combiner>;
+               reg = <0x13930000 0x1000>;
+               interrupt-names = "lcd_sys", "vsync", "fifo";
+               interrupts = <0 188 0>, <0 189 0>, <0 190 0>;
+               clocks = <&clock_disp PCLK_DECON_INT>,
+                        <&clock_disp ACLK_DECON_INT>,
+                        <&clock_disp SCLK_DECON_INT_ECLK>,
+                        <&clock_disp SCLK_DECON_INT_EXTCLKPLL>;
+               clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk",
+                               "decon0_vclk";
+               status = "disabled";
+       };
+
+Board specific DT entry:
+
+       decon@13930000 {
+               pinctrl-0 = <&lcd_clk &pwm1_out>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dp.txt
new file mode 100644 (file)
index 0000000..64693f2
--- /dev/null
@@ -0,0 +1,120 @@
+The Exynos display port interface should be configured based on
+the type of panel connected to it.
+
+We use two nodes:
+       -dp-controller node
+       -dptx-phy node(defined inside dp-controller node)
+
+For the DP-PHY initialization, we use the dptx-phy node.
+Required properties for dptx-phy: deprecated, use phys and phy-names
+       -reg: deprecated
+               Base address of DP PHY register.
+       -samsung,enable-mask: deprecated
+               The bit-mask used to enable/disable DP PHY.
+
+For the Panel initialization, we read data from dp-controller node.
+Required properties for dp-controller:
+       -compatible:
+               should be "samsung,exynos5-dp".
+       -reg:
+               physical base address of the controller and length
+               of memory mapped region.
+       -interrupts:
+               interrupt combiner values.
+       -clocks:
+               from common clock binding: handle to dp clock.
+       -clock-names:
+               from common clock binding: Shall be "dp".
+       -interrupt-parent:
+               phandle to Interrupt combiner node.
+       -phys:
+               from general PHY binding: the phandle for the PHY device.
+       -phy-names:
+               from general PHY binding: Should be "dp".
+       -samsung,color-space:
+               input video data format.
+                       COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2
+       -samsung,dynamic-range:
+               dynamic range for input video data.
+                       VESA = 0, CEA = 1
+       -samsung,ycbcr-coeff:
+               YCbCr co-efficients for input video.
+                       COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1
+       -samsung,color-depth:
+               number of bits per colour component.
+                       COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3
+       -samsung,link-rate:
+               link rate supported by the panel.
+                       LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A
+       -samsung,lane-count:
+               number of lanes supported by the panel.
+                       LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
+       - display-timings: timings for the connected panel as described by
+               Documentation/devicetree/bindings/display/display-timing.txt
+
+Optional properties for dp-controller:
+       -interlaced:
+               interlace scan mode.
+                       Progressive if defined, Interlaced if not defined
+       -vsync-active-high:
+               VSYNC polarity configuration.
+                       High if defined, Low if not defined
+       -hsync-active-high:
+               HSYNC polarity configuration.
+                       High if defined, Low if not defined
+       -samsung,hpd-gpio:
+               Hotplug detect GPIO.
+                       Indicates which GPIO should be used for hotplug
+                       detection
+       -video interfaces: Device node can contain video interface port
+                           nodes according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+SOC specific portion:
+       dp-controller {
+               compatible = "samsung,exynos5-dp";
+               reg = <0x145b0000 0x10000>;
+               interrupts = <10 3>;
+               interrupt-parent = <&combiner>;
+               clocks = <&clock 342>;
+               clock-names = "dp";
+
+               phys = <&dp_phy>;
+               phy-names = "dp";
+       };
+
+Board Specific portion:
+       dp-controller {
+               samsung,color-space = <0>;
+               samsung,dynamic-range = <0>;
+               samsung,ycbcr-coeff = <0>;
+               samsung,color-depth = <1>;
+               samsung,link-rate = <0x0a>;
+               samsung,lane-count = <4>;
+
+               display-timings {
+                       native-mode = <&lcd_timing>;
+                       lcd_timing: 1366x768 {
+                               clock-frequency = <70589280>;
+                               hactive = <1366>;
+                               vactive = <768>;
+                               hfront-porch = <40>;
+                               hback-porch = <40>;
+                               hsync-len = <32>;
+                               vback-porch = <10>;
+                               vfront-porch = <12>;
+                               vsync-len = <6>;
+                       };
+               };
+
+               ports {
+                       port@0 {
+                               dp_out: endpoint {
+                                       remote-endpoint = <&bridge_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt
new file mode 100644 (file)
index 0000000..0e6f0c0
--- /dev/null
@@ -0,0 +1,103 @@
+Exynos MIPI DSI Master
+
+Required properties:
+  - compatible: value should be one of the following
+               "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
+               "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
+               "samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
+               "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
+               "samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
+  - reg: physical base address and length of the registers set for the device
+  - interrupts: should contain DSI interrupt
+  - clocks: list of clock specifiers, must contain an entry for each required
+    entry in clock-names
+  - clock-names: should include "bus_clk"and "sclk_mipi" entries
+                the use of "pll_clk" is deprecated
+  - phys: list of phy specifiers, must contain an entry for each required
+    entry in phy-names
+  - phy-names: should include "dsim" entry
+  - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
+  - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
+  - samsung,pll-clock-frequency: specifies frequency of the oscillator clock
+  - #address-cells, #size-cells: should be set respectively to <1> and <0>
+    according to DSI host bindings (see MIPI DSI bindings [1])
+
+Optional properties:
+  - power-domains: a phandle to DSIM power domain node
+
+Child nodes:
+  Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
+
+Video interfaces:
+  Device node can contain video interface port nodes according to [2].
+  The following are properties specific to those nodes:
+
+  port node inbound:
+    - reg: (required) must be 0.
+  port node outbound:
+    - reg: (required) must be 1.
+
+  endpoint node connected from mic node (reg = 0):
+    - remote-endpoint: specifies the endpoint in mic node. This node is required
+                      for Exynos5433 mipi dsi. So mic can access to panel node
+                      thoughout this dsi node.
+  endpoint node connected to panel node (reg = 1):
+    - remote-endpoint: specifies the endpoint in panel node. This node is
+                      required in all kinds of exynos mipi dsi to represent
+                      the connection between mipi dsi and panel.
+    - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
+      mode
+    - samsung,esc-clock-frequency: specifies DSI frequency in escape mode
+
+[1]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       dsi@11C80000 {
+               compatible = "samsung,exynos4210-mipi-dsi";
+               reg = <0x11C80000 0x10000>;
+               interrupts = <0 79 0>;
+               clocks = <&clock 286>, <&clock 143>;
+               clock-names = "bus_clk", "sclk_mipi";
+               phys = <&mipi_phy 1>;
+               phy-names = "dsim";
+               vddcore-supply = <&vusb_reg>;
+               vddio-supply = <&vmipi_reg>;
+               power-domains = <&pd_lcd0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               samsung,pll-clock-frequency = <24000000>;
+
+               panel@1 {
+                       reg = <0>;
+                       ...
+                       port {
+                               panel_ep: endpoint {
+                                       remote-endpoint = <&dsi_ep>;
+                               };
+                       };
+               };
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               decon_to_mic: endpoint {
+                                       remote-endpoint = <&mic_to_decon>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               dsi_ep: endpoint {
+                                       reg = <0>;
+                                       samsung,burst-clock-frequency = <500000000>;
+                                       samsung,esc-clock-frequency = <20000000>;
+                                       remote-endpoint = <&panel_ep>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt b/Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
new file mode 100644 (file)
index 0000000..1fd8cf9
--- /dev/null
@@ -0,0 +1,43 @@
+Device-Tree bindings for drm hdmi driver
+
+Required properties:
+- compatible: value should be one among the following:
+       1) "samsung,exynos5-hdmi" <DEPRECATED>
+       2) "samsung,exynos4210-hdmi"
+       3) "samsung,exynos4212-hdmi"
+       4) "samsung,exynos5420-hdmi"
+- reg: physical base address of the hdmi and length of memory mapped
+       region.
+- interrupts: interrupt number to the cpu.
+- hpd-gpio: following information about the hotplug gpio pin.
+       a) phandle of the gpio controller node.
+       b) pin number within the gpio controller.
+       c) optional flags and pull up/down.
+- clocks: list of clock IDs from SoC clock driver.
+       a) hdmi: Gate of HDMI IP bus clock.
+       b) sclk_hdmi: Gate of HDMI special clock.
+       c) sclk_pixel: Pixel special clock, one of the two possible inputs of
+               HDMI clock mux.
+       d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
+               HDMI clock mux.
+       e) mout_hdmi: It is required by the driver to switch between the 2
+               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
+               after configuration, parent is set to sclk_hdmiphy else
+               sclk_pixel.
+- clock-names: aliases as per driver requirements for above clock IDs:
+       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
+- ddc: phandle to the hdmi ddc node
+- phy: phandle to the hdmi phy node
+- samsung,syscon-phandle: phandle for system controller node for PMU.
+
+Example:
+
+       hdmi {
+               compatible = "samsung,exynos4212-hdmi";
+               reg = <0x14530000 0x100000>;
+               interrupts = <0 95 0>;
+               hpd-gpio = <&gpx3 7 1>;
+               ddc = <&hdmi_ddc_node>;
+               phy = <&hdmi_phy_node>;
+               samsung,syscon-phandle = <&pmu_system_controller>;
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_hdmiddc.txt b/Documentation/devicetree/bindings/display/exynos/exynos_hdmiddc.txt
new file mode 100644 (file)
index 0000000..41eee97
--- /dev/null
@@ -0,0 +1,15 @@
+Device-Tree bindings for hdmiddc driver
+
+Required properties:
+- compatible: value should be one of the following
+       1) "samsung,exynos5-hdmiddc" <DEPRECATED>
+       2) "samsung,exynos4210-hdmiddc"
+
+- reg: I2C address of the hdmiddc device.
+
+Example:
+
+       hdmiddc {
+               compatible = "samsung,exynos4210-hdmiddc";
+               reg = <0x50>;
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_hdmiphy.txt b/Documentation/devicetree/bindings/display/exynos/exynos_hdmiphy.txt
new file mode 100644 (file)
index 0000000..162f641
--- /dev/null
@@ -0,0 +1,15 @@
+Device-Tree bindings for hdmiphy driver
+
+Required properties:
+- compatible: value should be one of the following:
+       1) "samsung,exynos5-hdmiphy" <DEPRECATED>
+       2) "samsung,exynos4210-hdmiphy".
+       3) "samsung,exynos4212-hdmiphy".
+- reg: I2C address of the hdmiphy device.
+
+Example:
+
+       hdmiphy {
+               compatible = "samsung,exynos4210-hdmiphy";
+               reg = <0x38>;
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_mixer.txt b/Documentation/devicetree/bindings/display/exynos/exynos_mixer.txt
new file mode 100644 (file)
index 0000000..3e38128
--- /dev/null
@@ -0,0 +1,26 @@
+Device-Tree bindings for mixer driver
+
+Required properties:
+- compatible: value should be one of the following:
+       1) "samsung,exynos5-mixer" <DEPRECATED>
+       2) "samsung,exynos4210-mixer"
+       3) "samsung,exynos4212-mixer"
+       4) "samsung,exynos5250-mixer"
+       5) "samsung,exynos5420-mixer"
+
+- reg: physical base address of the mixer and length of memory mapped
+       region.
+- interrupts: interrupt number to the cpu.
+- clocks: list of clock IDs from SoC clock driver.
+       a) mixer: Gate of Mixer IP bus clock.
+       b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of
+               mixer mux.
+       c) hdmi: Gate of HDMI IP bus clock, needed together with sclk_hdmi.
+
+Example:
+
+       mixer {
+               compatible = "samsung,exynos5250-mixer";
+               reg = <0x14450000 0x10000>;
+               interrupts = <0 94 0>;
+       };
diff --git a/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt b/Documentation/devicetree/bindings/display/exynos/samsung-fimd.txt
new file mode 100644 (file)
index 0000000..27c3ce0
--- /dev/null
@@ -0,0 +1,110 @@
+Device-Tree bindings for Samsung SoC display controller (FIMD)
+
+FIMD (Fully Interactive Mobile Display) is the Display Controller for the
+Samsung series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be one of the following
+               "samsung,s3c2443-fimd"; /* for S3C24XX SoCs */
+               "samsung,s3c6400-fimd"; /* for S3C64XX SoCs */
+               "samsung,s5pv210-fimd"; /* for S5PV210 SoC */
+               "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
+               "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
+               "samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
+               "samsung,exynos5250-fimd"; /* for Exynos5 SoCs */
+
+- reg: physical base address and length of the FIMD registers set.
+
+- interrupt-parent: should be the phandle of the fimd controller's
+               parent interrupt controller.
+
+- interrupts: should contain a list of all FIMD IP block interrupts in the
+                order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
+                format depends on the interrupt controller used.
+
+- interrupt-names: should contain the interrupt names: "fifo", "vsync",
+       "lcd_sys", in the same order as they were listed in the interrupts
+        property.
+
+- pinctrl-0: pin control group to be used for this controller.
+
+- pinctrl-names: must contain a "default" entry.
+
+- clocks: must include clock specifiers corresponding to entries in the
+         clock-names property.
+
+- clock-names: list of clock names sorted in the same order as the clocks
+               property. Must contain "sclk_fimd" and "fimd".
+
+Optional Properties:
+- power-domains: a phandle to FIMD power domain node.
+- samsung,invert-vden: video enable signal is inverted
+- samsung,invert-vclk: video clock signal is inverted
+- display-timings: timing settings for FIMD, as described in document [1].
+               Can be used in case timings cannot be provided otherwise
+               or to override timings provided by the panel.
+- samsung,sysreg: handle to syscon used to control the system registers
+- i80-if-timings: timing configuration for lcd i80 interface support.
+  - cs-setup: clock cycles for the active period of address signal is enabled
+              until chip select is enabled.
+              If not specified, the default value(0) will be used.
+  - wr-setup: clock cycles for the active period of CS signal is enabled until
+              write signal is enabled.
+              If not specified, the default value(0) will be used.
+  - wr-active: clock cycles for the active period of CS is enabled.
+               If not specified, the default value(1) will be used.
+  - wr-hold: clock cycles for the active period of CS is disabled until write
+             signal is disabled.
+             If not specified, the default value(0) will be used.
+
+  The parameters are defined as:
+
+    VCLK(internal)  __|??????|_____|??????|_____|??????|_____|??????|_____|??
+                      :            :            :            :            :
+    Address Output  --:<XXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XX
+                      | cs-setup+1 |            :            :            :
+                      |<---------->|            :            :            :
+    Chip Select     ???????????????|____________:____________:____________|??
+                                   | wr-setup+1 |            | wr-hold+1  |
+                                   |<---------->|            |<---------->|
+    Write Enable    ????????????????????????????|____________|???????????????
+                                                | wr-active+1|
+                                                |<---------->|
+    Video Data      ----------------------------<XXXXXXXXXXXXXXXXXXXXXXXXX>--
+
+The device node can contain 'port' child nodes according to the bindings defined
+in [2]. The following are properties specific to those nodes:
+- reg: (required) port index, can be:
+               0 - for CAMIF0 input,
+               1 - for CAMIF1 input,
+               2 - for CAMIF2 input,
+               3 - for parallel output,
+               4 - for write-back interface
+
+[1]: Documentation/devicetree/bindings/display/display-timing.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+SoC specific DT entry:
+
+       fimd@11c00000 {
+               compatible = "samsung,exynos4210-fimd";
+               interrupt-parent = <&combiner>;
+               reg = <0x11c00000 0x20000>;
+               interrupt-names = "fifo", "vsync", "lcd_sys";
+               interrupts = <11 0>, <11 1>, <11 2>;
+               clocks = <&clock 140>, <&clock 283>;
+               clock-names = "sclk_fimd", "fimd";
+               power-domains = <&pd_lcd0>;
+               status = "disabled";
+       };
+
+Board specific DT entry:
+
+       fimd@11c00000 {
+               pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
diff --git a/Documentation/devicetree/bindings/display/fsl,dcu.txt b/Documentation/devicetree/bindings/display/fsl,dcu.txt
new file mode 100644 (file)
index 0000000..ebf1be9
--- /dev/null
@@ -0,0 +1,22 @@
+Device Tree bindings for Freescale DCU DRM Driver
+
+Required properties:
+- compatible:          Should be one of
+       * "fsl,ls1021a-dcu".
+       * "fsl,vf610-dcu".
+
+- reg:                 Address and length of the register set for dcu.
+- clocks:              From common clock binding: handle to dcu clock.
+- clock-names:         From common clock binding: Shall be "dcu".
+- big-endian           Boolean property, LS1021A DCU registers are big-endian.
+- fsl,panel:           The phandle to panel node.
+
+Examples:
+dcu: dcu@2ce0000 {
+       compatible = "fsl,ls1021a-dcu";
+       reg = <0x0 0x2ce0000 0x0 0x10000>;
+       clocks = <&platform_clk 0>;
+       clock-names = "dcu";
+       big-endian;
+       fsl,panel = <&panel>;
+};
diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx-fb.txt b/Documentation/devicetree/bindings/display/imx/fsl,imx-fb.txt
new file mode 100644 (file)
index 0000000..00d5f8e
--- /dev/null
@@ -0,0 +1,55 @@
+Freescale imx21 Framebuffer
+
+This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
+
+Required properties:
+- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : One interrupt of the fb dev
+
+Required nodes:
+- display: Phandle to a display node as described in
+       Documentation/devicetree/bindings/display/display-timing.txt
+       Additional, the display node has to define properties:
+       - bits-per-pixel: Bits per pixel
+       - fsl,pcr: LCDC PCR value
+
+Optional properties:
+- lcd-supply: Regulator for LCD supply voltage.
+- fsl,dmacr: DMA Control Register value. This is optional. By default, the
+       register is not modified as recommended by the datasheet.
+- fsl,lpccr: Contrast Control Register value. This property provides the
+       default value for the contrast control register.
+       If that property is omitted, the register is zeroed.
+- fsl,lscr1: LCDC Sharp Configuration Register value.
+
+Example:
+
+       imxfb: fb@10021000 {
+               compatible = "fsl,imx21-fb";
+               interrupts = <61>;
+               reg = <0x10021000 0x1000>;
+               display = <&display0>;
+       };
+
+       ...
+
+       display0: display0 {
+               model = "Primeview-PD050VL1";
+               native-mode = <&timing_disp0>;
+               bits-per-pixel = <16>;
+               fsl,pcr = <0xf0c88080>; /* non-standard but required */
+               display-timings {
+                       timing_disp0: 640x480 {
+                               hactive = <640>;
+                               vactive = <480>;
+                               hback-porch = <112>;
+                               hfront-porch = <36>;
+                               hsync-len = <32>;
+                               vback-porch = <33>;
+                               vfront-porch = <33>;
+                               vsync-len = <2>;
+                               clock-frequency = <25000000>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt b/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt
new file mode 100644 (file)
index 0000000..971c3ee
--- /dev/null
@@ -0,0 +1,105 @@
+Freescale i.MX DRM master device
+================================
+
+The freescale i.MX DRM master device is a virtual device needed to list all
+IPU or other display interface nodes that comprise the graphics subsystem.
+
+Required properties:
+- compatible: Should be "fsl,imx-display-subsystem"
+- ports: Should contain a list of phandles pointing to display interface ports
+  of IPU devices
+
+example:
+
+display-subsystem {
+       compatible = "fsl,display-subsystem";
+       ports = <&ipu_di0>;
+};
+
+
+Freescale i.MX IPUv3
+====================
+
+Required properties:
+- compatible: Should be "fsl,<chip>-ipu"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain sync interrupt and error interrupt,
+  in this order.
+- resets: phandle pointing to the system reset controller and
+          reset line index, see reset/fsl,imx-src.txt for details
+Optional properties:
+- port@[0-3]: Port nodes with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+  Ports 0 and 1 should correspond to CSI0 and CSI1,
+  ports 2 and 3 should correspond to DI0 and DI1, respectively.
+
+example:
+
+ipu: ipu@18000000 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "fsl,imx53-ipu";
+       reg = <0x18000000 0x080000000>;
+       interrupts = <11 10>;
+       resets = <&src 2>;
+
+       ipu_di0: port@2 {
+               reg = <2>;
+
+               ipu_di0_disp0: endpoint {
+                       remote-endpoint = <&display_in>;
+               };
+       };
+};
+
+Parallel display support
+========================
+
+Required properties:
+- compatible: Should be "fsl,imx-parallel-display"
+Optional properties:
+- interface_pix_fmt: How this display is connected to the
+  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
+  and "lvds666".
+- edid: verbatim EDID data block describing attached display.
+- ddc: phandle describing the i2c bus handling the display data
+  channel
+- port@[0-1]: Port nodes with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+  Port 0 is the input port connected to the IPU display interface,
+  port 1 is the output port connected to a panel.
+
+example:
+
+display@di0 {
+       compatible = "fsl,imx-parallel-display";
+       edid = [edid-data];
+       interface-pix-fmt = "rgb24";
+
+       port@0 {
+               reg = <0>;
+
+               display_in: endpoint {
+                       remote-endpoint = <&ipu_di0_disp0>;
+               };
+       };
+
+       port@1 {
+               reg = <1>;
+
+               display_out: endpoint {
+                       remote-endpoint = <&panel_in>;
+               };
+       };
+};
+
+panel {
+       ...
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&display_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/imx/hdmi.txt b/Documentation/devicetree/bindings/display/imx/hdmi.txt
new file mode 100644 (file)
index 0000000..1b756cf
--- /dev/null
@@ -0,0 +1,58 @@
+Device-Tree bindings for HDMI Transmitter
+
+HDMI Transmitter
+================
+
+The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with accompanying PHY IP.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
+ - gpr : should be <&gpr>.
+   The phandle points to the iomuxc-gpr region containing the HDMI
+   multiplexer control register.
+ - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
+   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
+   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+ - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
+   Documentation/devicetree/bindings/media/video-interfaces.txt,
+   corresponding to the four inputs to the HDMI multiplexer.
+
+Optional properties:
+ - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+
+example:
+
+       gpr: iomuxc-gpr@020e0000 {
+               /* ... */
+       };
+
+        hdmi: hdmi@0120000 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                compatible = "fsl,imx6q-hdmi";
+                reg = <0x00120000 0x9000>;
+                interrupts = <0 115 0x04>;
+                gpr = <&gpr>;
+                clocks = <&clks 123>, <&clks 124>;
+                clock-names = "iahb", "isfr";
+                ddc-i2c-bus = <&i2c2>;
+
+                port@0 {
+                        reg = <0>;
+
+                        hdmi_mux_0: endpoint {
+                                remote-endpoint = <&ipu1_di0_hdmi>;
+                        };
+                };
+
+                port@1 {
+                        reg = <1>;
+
+                        hdmi_mux_1: endpoint {
+                                remote-endpoint = <&ipu1_di1_hdmi>;
+                        };
+                };
+        };
diff --git a/Documentation/devicetree/bindings/display/imx/ldb.txt b/Documentation/devicetree/bindings/display/imx/ldb.txt
new file mode 100644 (file)
index 0000000..0a175d9
--- /dev/null
@@ -0,0 +1,146 @@
+Device-Tree bindings for LVDS Display Bridge (ldb)
+
+LVDS Display Bridge
+===================
+
+The LVDS Display Bridge device tree node contains up to two lvds-channel
+nodes describing each of the two LVDS encoder channels of the bridge.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx53-ldb" or "fsl,imx6q-ldb".
+                Both LDB versions are similar, but i.MX6 has an additional
+                multiplexer in the front to select any of the four IPU display
+                interfaces as input for each LVDS channel.
+ - gpr : should be <&gpr> on i.MX53 and i.MX6q.
+         The phandle points to the iomuxc-gpr region containing the LVDS
+         control register.
+- clocks, clock-names : phandles to the LDB divider and selector clocks and to
+                        the display interface selector clocks, as described in
+                        Documentation/devicetree/bindings/clock/clock-bindings.txt
+        The following clocks are expected on i.MX53:
+                "di0_pll" - LDB LVDS channel 0 mux
+                "di1_pll" - LDB LVDS channel 1 mux
+                "di0" - LDB LVDS channel 0 gate
+                "di1" - LDB LVDS channel 1 gate
+                "di0_sel" - IPU1 DI0 mux
+                "di1_sel" - IPU1 DI1 mux
+        On i.MX6q the following additional clocks are needed:
+                "di2_sel" - IPU2 DI0 mux
+                "di3_sel" - IPU2 DI1 mux
+        The needed clock numbers for each are documented in
+        Documentation/devicetree/bindings/clock/imx5-clock.txt, and in
+        Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+
+Optional properties:
+ - pinctrl-names : should be "default" on i.MX53, not used on i.MX6q
+ - pinctrl-0 : a phandle pointing to LVDS pin settings on i.MX53,
+               not used on i.MX6q
+ - fsl,dual-channel : boolean. if it exists, only LVDS channel 0 should
+   be configured - one input will be distributed on both outputs in dual
+   channel mode
+
+LVDS Channel
+============
+
+Each LVDS Channel has to contain either an of graph link to a panel device node
+or a display-timings node that describes the video timings for the connected
+LVDS display as well as the fsl,data-mapping and fsl,data-width properties.
+
+Required properties:
+ - reg : should be <0> or <1>
+ - port: Input and output port nodes with endpoint definitions as defined in
+   Documentation/devicetree/bindings/graph.txt.
+   On i.MX5, the internal two-input-multiplexer is used. Due to hardware
+   limitations, only one input port (port@[0,1]) can be used for each channel
+   (lvds-channel@[0,1], respectively).
+   On i.MX6, there should be four input ports (port@[0-3]) that correspond
+   to the four LVDS multiplexer inputs.
+   A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected
+   to a panel input port. Optionally, the output port can be left out if
+   display-timings are used instead.
+
+Optional properties (required if display-timings are used):
+ - display-timings : A node that describes the display timings as defined in
+   Documentation/devicetree/bindings/display/display-timing.txt.
+ - fsl,data-mapping : should be "spwg" or "jeida"
+                      This describes how the color bits are laid out in the
+                      serialized LVDS signal.
+ - fsl,data-width : should be <18> or <24>
+
+example:
+
+gpr: iomuxc-gpr@53fa8000 {
+       /* ... */
+};
+
+ldb: ldb@53fa8008 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "fsl,imx53-ldb";
+       gpr = <&gpr>;
+       clocks = <&clks IMX5_CLK_LDB_DI0_SEL>,
+                <&clks IMX5_CLK_LDB_DI1_SEL>,
+                <&clks IMX5_CLK_IPU_DI0_SEL>,
+                <&clks IMX5_CLK_IPU_DI1_SEL>,
+                <&clks IMX5_CLK_LDB_DI0_GATE>,
+                <&clks IMX5_CLK_LDB_DI1_GATE>;
+       clock-names = "di0_pll", "di1_pll",
+                     "di0_sel", "di1_sel",
+                     "di0", "di1";
+
+       /* Using an of-graph endpoint link to connect the panel */
+       lvds-channel@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       lvds0_in: endpoint {
+                               remote-endpoint = <&ipu_di0_lvds0>;
+                       };
+               };
+
+               port@2 {
+                       reg = <2>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+
+       /* Using display-timings and fsl,data-mapping/width instead */
+       lvds-channel@1 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <1>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+
+               display-timings {
+                       /* ... */
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       lvds1_in: endpoint {
+                               remote-endpoint = <&ipu_di1_lvds1>;
+                       };
+               };
+       };
+};
+
+panel: lvds-panel {
+       /* ... */
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&lvds0_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/marvell,pxa2xx-lcdc.txt b/Documentation/devicetree/bindings/display/marvell,pxa2xx-lcdc.txt
new file mode 100644 (file)
index 0000000..309c47f
--- /dev/null
@@ -0,0 +1,34 @@
+PXA LCD Controller
+------------------
+
+Required properties:
+ - compatible : one of these
+       "marvell,pxa2xx-lcdc",
+       "marvell,pxa270-lcdc",
+       "marvell,pxa300-lcdc"
+ - reg : should contain 1 register range (address and length).
+ - interrupts : framebuffer controller interrupt.
+ - clocks: phandle to input clocks
+
+Required nodes:
+ - port: connection to the LCD panel (see video-interfaces.txt)
+        This node must have its properties bus-width and remote-endpoint set.
+        If the panel is not a TFT color panel, then a "lcd-type" property in
+        the panel should specify the panel type.
+        This panel node should be in the board dts.
+
+Example:
+       lcd-controller@40500000 {
+               compatible = "marvell,pxa2xx-lcdc";
+               reg = <0x44000000 0x10000>;
+               interrupts = <17>;
+               clocks = <&clks CLK_LCD>;
+               status = "okay";
+
+               port {
+                       lcdc_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                               bus-width = <16>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
new file mode 100644 (file)
index 0000000..973c272
--- /dev/null
@@ -0,0 +1,98 @@
+MIPI DSI (Display Serial Interface) busses
+==========================================
+
+The MIPI Display Serial Interface specifies a serial bus and a protocol for
+communication between a host and up to four peripherals. This document will
+define the syntax used to represent a DSI bus in a device tree.
+
+This document describes DSI bus-specific properties only or defines existing
+standard properties in the context of the DSI bus.
+
+Each DSI host provides a DSI bus. The DSI host controller's node contains a
+set of properties that characterize the bus. Child nodes describe individual
+peripherals on that bus.
+
+The following assumes that only a single peripheral is connected to a DSI
+host. Experience shows that this is true for the large majority of setups.
+
+DSI host
+--------
+
+In addition to the standard properties and those defined by the parent bus of
+a DSI host, the following properties apply to a node representing a DSI host.
+
+Required properties:
+- #address-cells: The number of cells required to represent an address on the
+  bus. DSI peripherals are addressed using a 2-bit virtual channel number, so
+  a maximum of 4 devices can be addressed on a single bus. Hence the value of
+  this property should be 1.
+- #size-cells: Should be 0. There are cases where it makes sense to use a
+  different value here. See below.
+
+DSI peripheral
+--------------
+
+Peripherals are represented as child nodes of the DSI host's node. Properties
+described here apply to all DSI peripherals, but individual bindings may want
+to define additional, device-specific properties.
+
+Required properties:
+- reg: The virtual channel number of a DSI peripheral. Must be in the range
+  from 0 to 3.
+
+Some DSI peripherals respond to more than a single virtual channel. In that
+case two alternative representations can be chosen:
+- The reg property can take multiple entries, one for each virtual channel
+  that the peripheral responds to.
+- If the virtual channels that a peripheral responds to are consecutive, the
+  #size-cells can be set to 1. The first cell of each entry in the reg
+  property is the number of the first virtual channel and the second cell is
+  the number of consecutive virtual channels.
+
+Example
+-------
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* peripheral responds to virtual channel 0 */
+               peripheral@0 {
+                       compatible = "...";
+                       reg = <0>;
+               };
+
+               ...
+       };
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* peripheral responds to virtual channels 0 and 2 */
+               peripheral@0 {
+                       compatible = "...";
+                       reg = <0, 2>;
+               };
+
+               ...
+       };
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* peripheral responds to virtual channels 1, 2 and 3 */
+               peripheral@1 {
+                       compatible = "...";
+                       reg = <1 3>;
+               };
+
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt
new file mode 100644 (file)
index 0000000..f344b9e
--- /dev/null
@@ -0,0 +1,149 @@
+Qualcomm Technologies Inc. adreno/snapdragon DSI output
+
+DSI Controller:
+Required properties:
+- compatible:
+  * "qcom,mdss-dsi-ctrl"
+- reg: Physical base address and length of the registers of controller
+- reg-names: The names of register regions. The following regions are required:
+  * "dsi_ctrl"
+- qcom,dsi-host-index: The ID of DSI controller hardware instance. This should
+  be 0 or 1, since we have 2 DSI controllers at most for now.
+- interrupts: The interrupt signal from the DSI block.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "bus_clk"
+  * "byte_clk"
+  * "core_clk"
+  * "core_mmss_clk"
+  * "iface_clk"
+  * "mdp_core_clk"
+  * "pixel_clk"
+- vdd-supply: phandle to vdd regulator device node
+- vddio-supply: phandle to vdd-io regulator device node
+- vdda-supply: phandle to vdda regulator device node
+- qcom,dsi-phy: phandle to DSI PHY device node
+
+Optional properties:
+- panel@0: Node of panel connected to this DSI controller.
+  See files in Documentation/devicetree/bindings/display/panel/ for each supported
+  panel.
+- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is
+  driving a panel which needs 2 DSI links.
+- qcom,master-dsi: Boolean value indicating if the DSI controller is driving
+  the master link of the 2-DSI panel.
+- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is
+  driving a 2-DSI panel whose 2 links need receive command simultaneously.
+- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
+  through MDP block
+- pinctrl-names: the pin control state names; should contain "default"
+- pinctrl-0: the default pinctrl state (active)
+- pinctrl-n: the "sleep" pinctrl state
+- port: DSI controller output port. This contains one endpoint subnode, with its
+  remote-endpoint set to the phandle of the connected panel's endpoint.
+  See Documentation/devicetree/bindings/graph.txt for device graph info.
+
+DSI PHY:
+Required properties:
+- compatible: Could be the following
+  * "qcom,dsi-phy-28nm-hpm"
+  * "qcom,dsi-phy-28nm-lp"
+  * "qcom,dsi-phy-20nm"
+- reg: Physical base address and length of the registers of PLL, PHY and PHY
+  regulator
+- reg-names: The names of register regions. The following regions are required:
+  * "dsi_pll"
+  * "dsi_phy"
+  * "dsi_phy_regulator"
+- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should
+  be 0 or 1, since we have 2 DSI PHYs at most for now.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "iface_clk"
+- vddio-supply: phandle to vdd-io regulator device node
+
+Optional properties:
+- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
+  regulator is wanted.
+
+Example:
+       mdss_dsi0: qcom,mdss_dsi@fd922800 {
+               compatible = "qcom,mdss-dsi-ctrl";
+               qcom,dsi-host-index = <0>;
+               interrupt-parent = <&mdss_mdp>;
+               interrupts = <4 0>;
+               reg-names = "dsi_ctrl";
+               reg = <0xfd922800 0x200>;
+               power-domains = <&mmcc MDSS_GDSC>;
+               clock-names =
+                       "bus_clk",
+                       "byte_clk",
+                       "core_clk",
+                       "core_mmss_clk",
+                       "iface_clk",
+                       "mdp_core_clk",
+                       "pixel_clk";
+               clocks =
+                       <&mmcc MDSS_AXI_CLK>,
+                       <&mmcc MDSS_BYTE0_CLK>,
+                       <&mmcc MDSS_ESC0_CLK>,
+                       <&mmcc MMSS_MISC_AHB_CLK>,
+                       <&mmcc MDSS_AHB_CLK>,
+                       <&mmcc MDSS_MDP_CLK>,
+                       <&mmcc MDSS_PCLK0_CLK>;
+               vdda-supply = <&pma8084_l2>;
+               vdd-supply = <&pma8084_l22>;
+               vddio-supply = <&pma8084_l12>;
+
+               qcom,dsi-phy = <&mdss_dsi_phy0>;
+
+               qcom,dual-dsi-mode;
+               qcom,master-dsi;
+               qcom,sync-dual-dsi;
+
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&mdss_dsi_active>;
+               pinctrl-1 = <&mdss_dsi_suspend>;
+
+               panel: panel@0 {
+                       compatible = "sharp,lq101r1sx01";
+                       reg = <0>;
+                       link2 = <&secondary>;
+
+                       power-supply = <...>;
+                       backlight = <...>;
+
+                       port {
+                               panel_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+               };
+
+               port {
+                       dsi0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+
+       mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 {
+               compatible = "qcom,dsi-phy-28nm-hpm";
+               qcom,dsi-phy-index = <0>;
+               reg-names =
+                       "dsi_pll",
+                       "dsi_phy",
+                       "dsi_phy_regulator";
+               reg =   <0xfd922a00 0xd4>,
+                       <0xfd922b00 0x2b0>,
+                       <0xfd922d80 0x7b>;
+               clock-names = "iface_clk";
+               clocks = <&mmcc MDSS_AHB_CLK>;
+               vddio-supply = <&pma8084_l12>;
+
+               qcom,dsi-phy-regulator-ldo-mode;
+       };
diff --git a/Documentation/devicetree/bindings/display/msm/edp.txt b/Documentation/devicetree/bindings/display/msm/edp.txt
new file mode 100644 (file)
index 0000000..3a20f6e
--- /dev/null
@@ -0,0 +1,60 @@
+Qualcomm Technologies Inc. adreno/snapdragon eDP output
+
+Required properties:
+- compatible:
+  * "qcom,mdss-edp"
+- reg: Physical base address and length of the registers of controller and PLL
+- reg-names: The names of register regions. The following regions are required:
+  * "edp"
+  * "pll_base"
+- interrupts: The interrupt signal from the eDP block.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "core_clk"
+  * "iface_clk"
+  * "mdp_core_clk"
+  * "pixel_clk"
+  * "link_clk"
+- #clock-cells: The value should be 1.
+- vdda-supply: phandle to vdda regulator device node
+- lvl-vdd-supply: phandle to regulator device node which is used to supply power
+  to HPD receiving chip
+- panel-en-gpios: GPIO pin to supply power to panel.
+- panel-hpd-gpios: GPIO pin used for eDP hpd.
+
+
+Optional properties:
+- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
+  through MDP block
+
+Example:
+       mdss_edp: qcom,mdss_edp@fd923400 {
+                       compatible = "qcom,mdss-edp";
+                       reg-names =
+                               "edp",
+                               "pll_base";
+                       reg =   <0xfd923400 0x700>,
+                               <0xfd923a00 0xd4>;
+                       interrupt-parent = <&mdss_mdp>;
+                       interrupts = <12 0>;
+                       power-domains = <&mmcc MDSS_GDSC>;
+                       clock-names =
+                               "core_clk",
+                               "pixel_clk",
+                               "iface_clk",
+                               "link_clk",
+                               "mdp_core_clk";
+                       clocks =
+                               <&mmcc MDSS_EDPAUX_CLK>,
+                               <&mmcc MDSS_EDPPIXEL_CLK>,
+                               <&mmcc MDSS_AHB_CLK>,
+                               <&mmcc MDSS_EDPLINK_CLK>,
+                               <&mmcc MDSS_MDP_CLK>;
+                       #clock-cells = <1>;
+                       vdda-supply = <&pma8084_l12>;
+                       lvl-vdd-supply = <&lvl_vreg>;
+                       panel-en-gpios = <&tlmm 137 0>;
+                       panel-hpd-gpios = <&tlmm 103 0>;
+       };
diff --git a/Documentation/devicetree/bindings/display/msm/gpu.txt b/Documentation/devicetree/bindings/display/msm/gpu.txt
new file mode 100644 (file)
index 0000000..67d0a58
--- /dev/null
@@ -0,0 +1,52 @@
+Qualcomm adreno/snapdragon GPU
+
+Required properties:
+- compatible: "qcom,adreno-3xx"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The interrupt signal from the gpu.
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "core_clk"
+  * "iface_clk"
+  * "mem_iface_clk"
+- qcom,chipid: gpu chip-id.  Note this may become optional for future
+  devices if we can reliably read the chipid from hw
+- qcom,gpu-pwrlevels: list of operating points
+  - compatible: "qcom,gpu-pwrlevels"
+  - for each qcom,gpu-pwrlevel:
+    - qcom,gpu-freq: requested gpu clock speed
+    - NOTE: downstream android driver defines additional parameters to
+      configure memory bandwidth scaling per OPP.
+
+Example:
+
+/ {
+       ...
+
+       gpu: qcom,kgsl-3d0@4300000 {
+               compatible = "qcom,adreno-3xx";
+               reg = <0x04300000 0x20000>;
+               reg-names = "kgsl_3d0_reg_memory";
+               interrupts = <GIC_SPI 80 0>;
+               interrupt-names = "kgsl_3d0_irq";
+               clock-names =
+                   "core_clk",
+                   "iface_clk",
+                   "mem_iface_clk";
+               clocks =
+                   <&mmcc GFX3D_CLK>,
+                   <&mmcc GFX3D_AHB_CLK>,
+                   <&mmcc MMSS_IMEM_AHB_CLK>;
+               qcom,chipid = <0x03020100>;
+               qcom,gpu-pwrlevels {
+                       compatible = "qcom,gpu-pwrlevels";
+                       qcom,gpu-pwrlevel@0 {
+                               qcom,gpu-freq = <450000000>;
+                       };
+                       qcom,gpu-pwrlevel@1 {
+                               qcom,gpu-freq = <27000000>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/msm/hdmi.txt b/Documentation/devicetree/bindings/display/msm/hdmi.txt
new file mode 100644 (file)
index 0000000..e926239
--- /dev/null
@@ -0,0 +1,55 @@
+Qualcomm adreno/snapdragon hdmi output
+
+Required properties:
+- compatible: one of the following
+   * "qcom,hdmi-tx-8994"
+   * "qcom,hdmi-tx-8084"
+   * "qcom,hdmi-tx-8974"
+   * "qcom,hdmi-tx-8660"
+   * "qcom,hdmi-tx-8960"
+- reg: Physical base address and length of the controller's registers
+- reg-names: "core_physical"
+- interrupts: The interrupt signal from the hdmi block.
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- qcom,hdmi-tx-ddc-clk-gpio: ddc clk pin
+- qcom,hdmi-tx-ddc-data-gpio: ddc data pin
+- qcom,hdmi-tx-hpd-gpio: hpd pin
+- core-vdda-supply: phandle to supply regulator
+- hdmi-mux-supply: phandle to mux regulator
+
+Optional properties:
+- qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin
+- qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin
+- pinctrl-names: the pin control state names; should contain "default"
+- pinctrl-0: the default pinctrl state (active)
+- pinctrl-1: the "sleep" pinctrl state
+
+Example:
+
+/ {
+       ...
+
+       hdmi: qcom,hdmi-tx-8960@4a00000 {
+               compatible = "qcom,hdmi-tx-8960";
+               reg-names = "core_physical";
+               reg = <0x04a00000 0x1000>;
+               interrupts = <GIC_SPI 79 0>;
+               clock-names =
+                   "core_clk",
+                   "master_iface_clk",
+                   "slave_iface_clk";
+               clocks =
+                   <&mmcc HDMI_APP_CLK>,
+                   <&mmcc HDMI_M_AHB_CLK>,
+                   <&mmcc HDMI_S_AHB_CLK>;
+               qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>;
+               qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>;
+               qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
+               core-vdda-supply = <&pm8921_hdmi_mvs>;
+               hdmi-mux-supply = <&ext_3p3v>;
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&hpd_active  &ddc_active  &cec_active>;
+               pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/msm/mdp.txt b/Documentation/devicetree/bindings/display/msm/mdp.txt
new file mode 100644 (file)
index 0000000..1a0598e
--- /dev/null
@@ -0,0 +1,48 @@
+Qualcomm adreno/snapdragon display controller
+
+Required properties:
+- compatible:
+  * "qcom,mdp" - mdp4
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The interrupt signal from the display controller.
+- connectors: array of phandles for output device(s)
+- clocks: device clocks
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "core_clk"
+  * "iface_clk"
+  * "lut_clk"
+  * "src_clk"
+  * "hdmi_clk"
+  * "mpd_clk"
+
+Optional properties:
+- gpus: phandle for gpu device
+
+Example:
+
+/ {
+       ...
+
+       mdp: qcom,mdp@5100000 {
+               compatible = "qcom,mdp";
+               reg = <0x05100000 0xf0000>;
+               interrupts = <GIC_SPI 75 0>;
+               connectors = <&hdmi>;
+               gpus = <&gpu>;
+               clock-names =
+                   "core_clk",
+                   "iface_clk",
+                   "lut_clk",
+                   "src_clk",
+                   "hdmi_clk",
+                   "mdp_clk";
+               clocks =
+                   <&mmcc MDP_SRC>,
+                   <&mmcc MDP_AHB_CLK>,
+                   <&mmcc MDP_LUT_CLK>,
+                   <&mmcc TV_SRC>,
+                   <&mmcc HDMI_TV_CLK>,
+                   <&mmcc MDP_TV_CLK>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/mxsfb.txt b/Documentation/devicetree/bindings/display/mxsfb.txt
new file mode 100644 (file)
index 0000000..96ec517
--- /dev/null
@@ -0,0 +1,49 @@
+* Freescale MXS LCD Interface (LCDIF)
+
+Required properties:
+- compatible: Should be "fsl,<chip>-lcdif".  Supported chips include
+  imx23 and imx28.
+- reg: Address and length of the register set for lcdif
+- interrupts: Should contain lcdif interrupts
+- display : phandle to display node (see below for details)
+
+* display node
+
+Required properties:
+- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
+- bus-width : number of data lines.  Could be <8>, <16>, <18> or <24>.
+
+Required sub-node:
+- display-timings : Refer to binding doc display-timing.txt for details.
+
+Examples:
+
+lcdif@80030000 {
+       compatible = "fsl,imx28-lcdif";
+       reg = <0x80030000 2000>;
+       interrupts = <38 86>;
+
+       display: display {
+               bits-per-pixel = <32>;
+               bus-width = <24>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: timing0 {
+                               clock-frequency = <33500000>;
+                               hactive = <800>;
+                               vactive = <480>;
+                               hfront-porch = <164>;
+                               hback-porch = <89>;
+                               hsync-len = <10>;
+                               vback-porch = <23>;
+                               vfront-porch = <10>;
+                               vsync-len = <10>;
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               de-active = <1>;
+                               pixelclk-active = <0>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt b/Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt
new file mode 100644 (file)
index 0000000..83e2cae
--- /dev/null
@@ -0,0 +1,7 @@
+Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "ampire,am800480r3tmqwa1h"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt b/Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt
new file mode 100644 (file)
index 0000000..bae0e2b
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 8.0" WUXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101ean01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt
new file mode 100644 (file)
index 0000000..72e088a
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101aw03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt b/Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt
new file mode 100644 (file)
index 0000000..3590b07
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101ean01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt
new file mode 100644 (file)
index 0000000..889d511
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101xtn01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt b/Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt
new file mode 100644 (file)
index 0000000..690d0a5
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
+
+Required properties:
+- compatible: should be "auo,b116xw03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt
new file mode 100644 (file)
index 0000000..302226b
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
+
+Required properties:
+- compatible: should be "auo,b133htn01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt
new file mode 100644 (file)
index 0000000..7443b7c
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b133xtn01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt b/Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt
new file mode 100644 (file)
index 0000000..b6f2f3e
--- /dev/null
@@ -0,0 +1,7 @@
+Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
+
+Required properties:
+- compatible: should be "avic,tm070ddh03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt
new file mode 100644 (file)
index 0000000..f24614e
--- /dev/null
@@ -0,0 +1,7 @@
+Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "chunghwa,claa101wa01a"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt
new file mode 100644 (file)
index 0000000..0ab2c05
--- /dev/null
@@ -0,0 +1,7 @@
+Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "chunghwa,claa101wb03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/display-timing.txt b/Documentation/devicetree/bindings/display/panel/display-timing.txt
new file mode 100644 (file)
index 0000000..e1d4a0b
--- /dev/null
@@ -0,0 +1,110 @@
+display-timing bindings
+=======================
+
+display-timings node
+--------------------
+
+required properties:
+ - none
+
+optional properties:
+ - native-mode: The native mode for the display, in case multiple modes are
+               provided. When omitted, assume the first node is the native.
+
+timing subnode
+--------------
+
+required properties:
+ - hactive, vactive: display resolution
+ - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters
+   in pixels
+   vfront-porch, vback-porch, vsync-len: vertical display timing parameters in
+   lines
+ - clock-frequency: display clock in Hz
+
+optional properties:
+ - hsync-active: hsync pulse is active low/high/ignored
+ - vsync-active: vsync pulse is active low/high/ignored
+ - de-active: data-enable pulse is active low/high/ignored
+ - pixelclk-active: with
+                       - active high = drive pixel data on rising edge/
+                                       sample data on falling edge
+                       - active low  = drive pixel data on falling edge/
+                                       sample data on rising edge
+                       - ignored     = ignored
+ - interlaced (bool): boolean to enable interlaced mode
+ - doublescan (bool): boolean to enable doublescan mode
+ - doubleclk (bool): boolean to enable doubleclock mode
+
+All the optional properties that are not bool follow the following logic:
+    <1>: high active
+    <0>: low active
+    omitted: not used on hardware
+
+There are different ways of describing the capabilities of a display. The
+devicetree representation corresponds to the one commonly found in datasheets
+for displays. If a display supports multiple signal timings, the native-mode
+can be specified.
+
+The parameters are defined as:
+
+  +----------+-------------------------------------+----------+-------+
+  |          |        â†‘                            |          |       |
+  |          |        |vback_porch                 |          |       |
+  |          |        â†“                            |          |       |
+  +----------#######################################----------+-------+
+  |          #        â†‘                            #          |       |
+  |          #        |                            #          |       |
+  |  hback   #        |                            #  hfront  | hsync |
+  |   porch  #        |       hactive              #  porch   |  len  |
+  |<-------->#<-------+--------------------------->#<-------->|<----->|
+  |          #        |                            #          |       |
+  |          #        |vactive                     #          |       |
+  |          #        |                            #          |       |
+  |          #        â†“                            #          |       |
+  +----------#######################################----------+-------+
+  |          |        â†‘                            |          |       |
+  |          |        |vfront_porch                |          |       |
+  |          |        â†“                            |          |       |
+  +----------+-------------------------------------+----------+-------+
+  |          |        â†‘                            |          |       |
+  |          |        |vsync_len                   |          |       |
+  |          |        â†“                            |          |       |
+  +----------+-------------------------------------+----------+-------+
+
+Example:
+
+       display-timings {
+               native-mode = <&timing0>;
+               timing0: 1080p24 {
+                       /* 1920x1080p24 */
+                       clock-frequency = <52000000>;
+                       hactive = <1920>;
+                       vactive = <1080>;
+                       hfront-porch = <25>;
+                       hback-porch = <25>;
+                       hsync-len = <25>;
+                       vback-porch = <2>;
+                       vfront-porch = <2>;
+                       vsync-len = <2>;
+                       hsync-active = <1>;
+               };
+       };
+
+Every required property also supports the use of ranges, so the commonly used
+datasheet description with minimum, typical and maximum values can be used.
+
+Example:
+
+       timing1: timing {
+               /* 1920x1080p24 */
+               clock-frequency = <148500000>;
+               hactive = <1920>;
+               vactive = <1080>;
+               hsync-len = <0 44 60>;
+               hfront-porch = <80 88 95>;
+               hback-porch = <100 148 160>;
+               vfront-porch = <0 4 6>;
+               vback-porch = <0 36 50>;
+               vsync-len = <0 5 6>;
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt b/Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt
new file mode 100644 (file)
index 0000000..4903d7b
--- /dev/null
@@ -0,0 +1,7 @@
+Emerging Display Technology Corp. 5.7" VGA TFT LCD panel
+
+Required properties:
+- compatible: should be "edt,et057090dhu"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt b/Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt
new file mode 100644 (file)
index 0000000..20cb38e
--- /dev/null
@@ -0,0 +1,10 @@
+Emerging Display Technology Corp. ET070080DH6 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "edt,et070080dh6"
+
+This panel is the same as ETM0700G0DH6 except for the touchscreen.
+ET070080DH6 is the model with resistive touch.
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt b/Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt
new file mode 100644 (file)
index 0000000..ee4b180
--- /dev/null
@@ -0,0 +1,10 @@
+Emerging Display Technology Corp. ETM0700G0DH6 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "edt,etm0700g0dh6"
+
+This panel is the same as ET070080DH6 except for the touchscreen.
+ETM0700G0DH6 is the model with capacitive multitouch.
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt b/Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt
new file mode 100644 (file)
index 0000000..b47f9d8
--- /dev/null
@@ -0,0 +1,7 @@
+Foxlink Group 5" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "foxlink,fl500wvr00-a0t"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt b/Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt
new file mode 100644 (file)
index 0000000..24b0b62
--- /dev/null
@@ -0,0 +1,7 @@
+GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "giantplus,gpg48273qs5"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt b/Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt
new file mode 100644 (file)
index 0000000..7da1d5c
--- /dev/null
@@ -0,0 +1,7 @@
+HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "hannstar,hsd070pww1"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt b/Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt
new file mode 100644 (file)
index 0000000..8270319
--- /dev/null
@@ -0,0 +1,7 @@
+HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
+
+Required properties:
+- compatible: should be "hannstar,hsd100pxn1"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt b/Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt
new file mode 100644 (file)
index 0000000..04caaae
--- /dev/null
@@ -0,0 +1,7 @@
+Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
+
+Required properties:
+- compatible: should be "hit,tx23d38vm0caa"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt b/Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt
new file mode 100644 (file)
index 0000000..4104226
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux AT043TN24 4.3" WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,at043tn24"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt
new file mode 100644 (file)
index 0000000..2743b07
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,g121i1-l01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt b/Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt
new file mode 100644 (file)
index 0000000..081bb93
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,n116bge"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt b/Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt
new file mode 100644 (file)
index 0000000..7825844
--- /dev/null
@@ -0,0 +1,7 @@
+InnoLux 15.6" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,n156bge-l21"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt b/Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt
new file mode 100644 (file)
index 0000000..824f87f
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,zj070na-01p"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt b/Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt
new file mode 100644 (file)
index 0000000..a7588e5
--- /dev/null
@@ -0,0 +1,7 @@
+LG 7" (800x480 pixels) TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lb070wv8"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,ld070wx3-sl01.txt b/Documentation/devicetree/bindings/display/panel/lg,ld070wx3-sl01.txt
new file mode 100644 (file)
index 0000000..5e649cb
--- /dev/null
@@ -0,0 +1,7 @@
+LG Corporation 7" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,ld070wx3-sl01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lg4573.txt b/Documentation/devicetree/bindings/display/panel/lg,lg4573.txt
new file mode 100644 (file)
index 0000000..824441f
--- /dev/null
@@ -0,0 +1,19 @@
+LG LG4573 TFT Liquid Crystal Display with SPI control bus
+
+Required properties:
+  - compatible: "lg,lg4573"
+  - reg: address of the panel on the SPI bus
+
+The panel must obey rules for SPI slave device specified in document [1].
+
+[1]: Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+       lcd_panel: display@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "lg,lg4573";
+               spi-max-frequency = <10000000>;
+               reg = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lh500wx1-sd03.txt b/Documentation/devicetree/bindings/display/panel/lg,lh500wx1-sd03.txt
new file mode 100644 (file)
index 0000000..a04fd2b
--- /dev/null
@@ -0,0 +1,7 @@
+LG Corporation 5" HD TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lh500wx1-sd03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt b/Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt
new file mode 100644 (file)
index 0000000..9f262e0
--- /dev/null
@@ -0,0 +1,7 @@
+LG 12.9" (2560x1700 pixels) TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lp129qe"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lgphilips,lb035q02.txt b/Documentation/devicetree/bindings/display/panel/lgphilips,lb035q02.txt
new file mode 100644 (file)
index 0000000..1a1e653
--- /dev/null
@@ -0,0 +1,33 @@
+LG.Philips LB035Q02 Panel
+=========================
+
+Required properties:
+- compatible: "lgphilips,lb035q02"
+- enable-gpios: panel enable gpio
+
+Optional properties:
+- label: a symbolic name for the panel
+
+Required nodes:
+- Video port for DPI input
+
+Example
+-------
+
+lcd-panel: panel@0 {
+       compatible = "lgphilips,lb035q02";
+       reg = <0>;
+       spi-max-frequency = <100000>;
+       spi-cpol;
+       spi-cpha;
+
+       label = "lcd";
+
+       enable-gpios = <&gpio7 7 0>;
+
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&dpi_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt b/Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt
new file mode 100644 (file)
index 0000000..8e1914d
--- /dev/null
@@ -0,0 +1,7 @@
+NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "nec,nl4827hc19-05b"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt b/Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt
new file mode 100644 (file)
index 0000000..ddf8e21
--- /dev/null
@@ -0,0 +1,7 @@
+OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel
+
+Required properties:
+- compatible: should be "okaya,rs800480t-7x0gp"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt b/Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt
new file mode 100644 (file)
index 0000000..de19e93
--- /dev/null
@@ -0,0 +1,7 @@
+OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
+
+Required properties:
+- compatible: should be "ortustech,com43h4m85ulc"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt
new file mode 100644 (file)
index 0000000..d328b03
--- /dev/null
@@ -0,0 +1,7 @@
+Panasonic Corporation 10.1" WUXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "panasonic,vvx10f004b00"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.txt b/Documentation/devicetree/bindings/display/panel/panel-dpi.txt
new file mode 100644 (file)
index 0000000..216c894
--- /dev/null
@@ -0,0 +1,45 @@
+Generic MIPI DPI Panel
+======================
+
+Required properties:
+- compatible: "panel-dpi"
+
+Optional properties:
+- label: a symbolic name for the panel
+- enable-gpios: panel enable gpio
+
+Required nodes:
+- "panel-timing" containing video timings
+  (Documentation/devicetree/bindings/display/display-timing.txt)
+- Video port for DPI input
+
+Example
+-------
+
+lcd0: display@0 {
+        compatible = "samsung,lte430wq-f0c", "panel-dpi";
+        label = "lcd";
+
+        port {
+            lcd_in: endpoint {
+                    remote-endpoint = <&dpi_out>;
+            };
+        };
+
+        panel-timing {
+                clock-frequency = <9200000>;
+                hactive = <480>;
+                vactive = <272>;
+                hfront-porch = <8>;
+                hback-porch = <4>;
+                hsync-len = <41>;
+                vback-porch = <2>;
+                vfront-porch = <4>;
+                vsync-len = <10>;
+
+                hsync-active = <0>;
+                vsync-active = <0>;
+                de-active = <1>;
+                pixelclk-active = <1>;
+        };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/panel-dsi-cm.txt b/Documentation/devicetree/bindings/display/panel/panel-dsi-cm.txt
new file mode 100644 (file)
index 0000000..dce48eb
--- /dev/null
@@ -0,0 +1,29 @@
+Generic MIPI DSI Command Mode Panel
+===================================
+
+Required properties:
+- compatible: "panel-dsi-cm"
+
+Optional properties:
+- label: a symbolic name for the panel
+- reset-gpios: panel reset gpio
+- te-gpios: panel TE gpio
+
+Required nodes:
+- Video port for DSI input
+
+Example
+-------
+
+lcd0: display {
+       compatible = "tpo,taal", "panel-dsi-cm";
+       label = "lcd0";
+
+       reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
+
+       port {
+               lcd0_in: endpoint {
+                       remote-endpoint = <&dsi1_out_ep>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ld9040.txt b/Documentation/devicetree/bindings/display/panel/samsung,ld9040.txt
new file mode 100644 (file)
index 0000000..fc595d9
--- /dev/null
@@ -0,0 +1,66 @@
+Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus
+
+Required properties:
+  - compatible: "samsung,ld9040"
+  - reg: address of the panel on SPI bus
+  - vdd3-supply: core voltage supply
+  - vci-supply: voltage supply for analog circuits
+  - reset-gpios: a GPIO spec for the reset pin
+  - display-timings: timings for the connected panel according to [1]
+
+The panel must obey rules for SPI slave device specified in document [2].
+
+Optional properties:
+  - power-on-delay: delay after turning regulators on [ms]
+  - reset-delay: delay after reset sequence [ms]
+  - panel-width-mm: physical panel width [mm]
+  - panel-height-mm: physical panel height [mm]
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [3]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/display/display-timing.txt
+[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
+[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       lcd@0 {
+               compatible = "samsung,ld9040";
+               reg = <0>;
+               vdd3-supply = <&ldo7_reg>;
+               vci-supply = <&ldo17_reg>;
+               reset-gpios = <&gpy4 5 0>;
+               spi-max-frequency = <1200000>;
+               spi-cpol;
+               spi-cpha;
+               power-on-delay = <10>;
+               reset-delay = <10>;
+               panel-width-mm = <90>;
+               panel-height-mm = <154>;
+
+               display-timings {
+                       timing {
+                               clock-frequency = <23492370>;
+                               hactive = <480>;
+                               vactive = <800>;
+                               hback-porch = <16>;
+                               hfront-porch = <16>;
+                               vback-porch = <2>;
+                               vfront-porch = <28>;
+                               hsync-len = <2>;
+                               vsync-len = <1>;
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               de-active = <0>;
+                               pixelclk-active = <0>;
+                       };
+               };
+
+               port {
+                       lcd_ep: endpoint {
+                               remote-endpoint = <&fimd_dpi_ep>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt b/Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt
new file mode 100644 (file)
index 0000000..ef522c6
--- /dev/null
@@ -0,0 +1,7 @@
+Samsung Electronics 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "samsung,ltn101nt05"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt b/Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt
new file mode 100644 (file)
index 0000000..e7f969d
--- /dev/null
@@ -0,0 +1,7 @@
+Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "samsung,ltn140at29-301"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.txt
new file mode 100644 (file)
index 0000000..25701c8
--- /dev/null
@@ -0,0 +1,56 @@
+Samsung S6E8AA0 AMOLED LCD 5.3 inch panel
+
+Required properties:
+  - compatible: "samsung,s6e8aa0"
+  - reg: the virtual channel number of a DSI peripheral
+  - vdd3-supply: core voltage supply
+  - vci-supply: voltage supply for analog circuits
+  - reset-gpios: a GPIO spec for the reset pin
+  - display-timings: timings for the connected panel as described by [1]
+
+Optional properties:
+  - power-on-delay: delay after turning regulators on [ms]
+  - reset-delay: delay after reset sequence [ms]
+  - init-delay: delay after initialization sequence [ms]
+  - panel-width-mm: physical panel width [mm]
+  - panel-height-mm: physical panel height [mm]
+  - flip-horizontal: boolean to flip image horizontally
+  - flip-vertical: boolean to flip image vertically
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [2]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/display/display-timing.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       panel {
+               compatible = "samsung,s6e8aa0";
+               reg = <0>;
+               vdd3-supply = <&vcclcd_reg>;
+               vci-supply = <&vlcd_reg>;
+               reset-gpios = <&gpy4 5 0>;
+               power-on-delay= <50>;
+               reset-delay = <100>;
+               init-delay = <100>;
+               panel-width-mm = <58>;
+               panel-height-mm = <103>;
+               flip-horizontal;
+               flip-vertical;
+
+               display-timings {
+                       timing0: timing-0 {
+                               clock-frequency = <57153600>;
+                               hactive = <720>;
+                               vactive = <1280>;
+                               hfront-porch = <5>;
+                               hback-porch = <5>;
+                               hsync-len = <5>;
+                               vfront-porch = <13>;
+                               vback-porch = <1>;
+                               vsync-len = <2>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.txt
new file mode 100644 (file)
index 0000000..f522bb8
--- /dev/null
@@ -0,0 +1,49 @@
+Sharp Microelectronics 10.1" WQXGA TFT LCD panel
+
+This panel requires a dual-channel DSI host to operate. It supports two modes:
+- left-right: each channel drives the left or right half of the screen
+- even-odd: each channel drives the even or odd lines of the screen
+
+Each of the DSI channels controls a separate DSI peripheral. The peripheral
+driven by the first link (DSI-LINK1), left or even, is considered the primary
+peripheral and controls the device. The 'link2' property contains a phandle
+to the peripheral driven by the second link (DSI-LINK2, right or odd).
+
+Note that in video mode the DSI-LINK1 interface always provides the left/even
+pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it
+is possible to program either link to drive the left/even or right/odd pixels
+but for the sake of consistency this binding assumes that the same assignment
+is chosen as for video mode.
+
+Required properties:
+- compatible: should be "sharp,lq101r1sx01"
+- reg: DSI virtual channel of the peripheral
+
+Required properties (for DSI-LINK1 only):
+- link2: phandle to the DSI peripheral on the secondary link. Note that the
+  presence of this property marks the containing node as DSI-LINK1.
+- power-supply: phandle of the regulator that provides the supply voltage
+
+Optional properties (for DSI-LINK1 only):
+- backlight: phandle of the backlight device attached to the panel
+
+Example:
+
+       dsi@54300000 {
+               panel: panel@0 {
+                       compatible = "sharp,lq101r1sx01";
+                       reg = <0>;
+
+                       link2 = <&secondary>;
+
+                       power-supply = <...>;
+                       backlight = <...>;
+               };
+       };
+
+       dsi@54400000 {
+               secondary: panel@0 {
+                       compatible = "sharp,lq101r1sx01";
+                       reg = <0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ls037v7dw01.txt b/Documentation/devicetree/bindings/display/panel/sharp,ls037v7dw01.txt
new file mode 100644 (file)
index 0000000..0cc8981
--- /dev/null
@@ -0,0 +1,43 @@
+SHARP LS037V7DW01 TFT-LCD panel
+===================================
+
+Required properties:
+- compatible: "sharp,ls037v7dw01"
+
+Optional properties:
+- label: a symbolic name for the panel
+- enable-gpios: a GPIO spec for the optional enable pin.
+  This pin is the INI pin as specified in the LS037V7DW01.pdf file.
+- reset-gpios: a GPIO spec for the optional reset pin.
+  This pin is the RESB pin as specified in the LS037V7DW01.pdf file.
+- mode-gpios: a GPIO
+  ordered MO, LR, and UD as specified in the LS037V7DW01.pdf file.
+
+Required nodes:
+- Video port for DPI input
+
+This panel can have zero to five GPIOs to configure to change configuration
+between QVGA and VGA mode and the scan direction. As these pins can be also
+configured with external pulls, all the GPIOs are considered optional with holes
+in the array.
+
+Example
+-------
+
+Example when connected to a omap2+ based device:
+
+lcd0: display {
+       compatible = "sharp,ls037v7dw01";
+       power-supply = <&lcd_3v3>;
+       enable-gpios = <&gpio5 24 GPIO_ACTIVE_HIGH>;    /* gpio152, lcd INI */
+       reset-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;     /* gpio155, lcd RESB */
+       mode-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH        /* gpio154, lcd MO */
+                     &gpio1 2 GPIO_ACTIVE_HIGH         /* gpio2, lcd LR */
+                     &gpio1 3 GPIO_ACTIVE_HIGH>;       /* gpio3, lcd UD */
+
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&dpi_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt b/Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt
new file mode 100644 (file)
index 0000000..fc1ea9e
--- /dev/null
@@ -0,0 +1,7 @@
+Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "shelly,sca07010-bfn-lnn"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/simple-panel.txt b/Documentation/devicetree/bindings/display/panel/simple-panel.txt
new file mode 100644 (file)
index 0000000..1341bbf
--- /dev/null
@@ -0,0 +1,21 @@
+Simple display panel
+
+Required properties:
+- power-supply: regulator to provide the supply voltage
+
+Optional properties:
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- enable-gpios: GPIO pin to enable or disable the panel
+- backlight: phandle of the backlight device attached to the panel
+
+Example:
+
+       panel: panel {
+               compatible = "cptt,claa101wb01";
+               ddc-i2c-bus = <&panelddc>;
+
+               power-supply = <&vdd_pnl_reg>;
+               enable-gpios = <&gpio 90 0>;
+
+               backlight = <&backlight>;
+       };
diff --git a/Documentation/devicetree/bindings/display/panel/sony,acx565akm.txt b/Documentation/devicetree/bindings/display/panel/sony,acx565akm.txt
new file mode 100644 (file)
index 0000000..e123332
--- /dev/null
@@ -0,0 +1,30 @@
+Sony ACX565AKM SDI Panel
+========================
+
+Required properties:
+- compatible: "sony,acx565akm"
+
+Optional properties:
+- label: a symbolic name for the panel
+- reset-gpios: panel reset gpio
+
+Required nodes:
+- Video port for SDI input
+
+Example
+-------
+
+acx565akm@2 {
+       compatible = "sony,acx565akm";
+       spi-max-frequency = <6000000>;
+       reg = <2>;
+
+       label = "lcd";
+       reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */
+
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&sdi_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt b/Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt
new file mode 100644 (file)
index 0000000..7175dc3
--- /dev/null
@@ -0,0 +1,30 @@
+Toppoly TD028TTEC1 Panel
+========================
+
+Required properties:
+- compatible: "toppoly,td028ttec1"
+
+Optional properties:
+- label: a symbolic name for the panel
+
+Required nodes:
+- Video port for DPI input
+
+Example
+-------
+
+lcd-panel: td028ttec1@0 {
+       compatible = "toppoly,td028ttec1";
+       reg = <0>;
+       spi-max-frequency = <100000>;
+       spi-cpol;
+       spi-cpha;
+
+       label = "lcd";
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&dpi_out>;
+               };
+       };
+};
+
diff --git a/Documentation/devicetree/bindings/display/panel/tpo,td043mtea1.txt b/Documentation/devicetree/bindings/display/panel/tpo,td043mtea1.txt
new file mode 100644 (file)
index 0000000..ec6d629
--- /dev/null
@@ -0,0 +1,33 @@
+TPO TD043MTEA1 Panel
+====================
+
+Required properties:
+- compatible: "tpo,td043mtea1"
+- reset-gpios: panel reset gpio
+
+Optional properties:
+- label: a symbolic name for the panel
+
+Required nodes:
+- Video port for DPI input
+
+Example
+-------
+
+lcd-panel: panel@0 {
+       compatible = "tpo,td043mtea1";
+       reg = <0>;
+       spi-max-frequency = <100000>;
+       spi-cpol;
+       spi-cpha;
+
+       label = "lcd";
+
+       reset-gpios = <&gpio7 7 0>;
+
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&dpi_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt
new file mode 100644 (file)
index 0000000..c902323
--- /dev/null
@@ -0,0 +1,88 @@
+* Renesas R-Car Display Unit (DU)
+
+Required Properties:
+
+  - compatible: must be one of the following.
+    - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
+    - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
+    - "renesas,du-r8a7791" for R8A7791 (R-Car M2) compatible DU
+
+  - reg: A list of base address and length of each memory resource, one for
+    each entry in the reg-names property.
+  - reg-names: Name of the memory resources. The DU requires one memory
+    resource for the DU core (named "du") and one memory resource for each
+    LVDS encoder (named "lvds.x" with "x" being the LVDS controller numerical
+    index).
+
+  - interrupt-parent: phandle of the parent interrupt controller.
+  - interrupts: Interrupt specifiers for the DU interrupts.
+
+  - clocks: A list of phandles + clock-specifier pairs, one for each entry in
+    the clock-names property.
+  - clock-names: Name of the clocks. This property is model-dependent.
+    - R8A7779 uses a single functional clock. The clock doesn't need to be
+      named.
+    - R8A7790 and R8A7791 use one functional clock per channel and one clock
+      per LVDS encoder. The functional clocks must be named "du.x" with "x"
+      being the channel numerical index. The LVDS clocks must be named
+      "lvds.x" with "x" being the LVDS encoder numerical index.
+    - In addition to the functional and encoder clocks, all DU versions also
+      support externally supplied pixel clocks. Those clocks are optional.
+      When supplied they must be named "dclkin.x" with "x" being the input
+      clock numerical index.
+
+Required nodes:
+
+The connections to the DU output video ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each DU output.
+
+               Port 0          Port1           Port2
+-----------------------------------------------------------------------------
+ R8A7779 (H1)  DPAD 0          DPAD 1          -
+ R8A7790 (H2)  DPAD            LVDS 0          LVDS 1
+ R8A7791 (M2)  DPAD            LVDS 0          -
+
+
+Example: R8A7790 (R-Car H2) DU
+
+       du: du@feb00000 {
+               compatible = "renesas,du-r8a7790";
+               reg = <0 0xfeb00000 0 0x70000>,
+                     <0 0xfeb90000 0 0x1c>,
+                     <0 0xfeb94000 0 0x1c>;
+               reg-names = "du", "lvds.0", "lvds.1";
+               interrupt-parent = <&gic>;
+               interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 268 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 269 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp7_clks R8A7790_CLK_DU0>,
+                        <&mstp7_clks R8A7790_CLK_DU1>,
+                        <&mstp7_clks R8A7790_CLK_DU2>,
+                        <&mstp7_clks R8A7790_CLK_LVDS0>,
+                        <&mstp7_clks R8A7790_CLK_LVDS1>;
+               clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               du_out_rgb: endpoint {
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               du_out_lvds0: endpoint {
+                               };
+                       };
+                       port@2 {
+                               reg = <2>;
+                               du_out_lvds1: endpoint {
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
new file mode 100644 (file)
index 0000000..668091f
--- /dev/null
@@ -0,0 +1,46 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: Physical base address and length of the controller's registers.
+- clocks: phandle to hdmi iahb and isfr clocks.
+- clock-names: should be "iahb" "isfr"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. For
+  vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+  rk3288 platform
+
+Optional properties
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+
+Example:
+hdmi: hdmi@ff980000 {
+       compatible = "rockchip,rk3288-dw-hdmi";
+       reg = <0xff980000 0x20000>;
+       reg-io-width = <4>;
+       ddc-i2c-bus = <&i2c5>;
+       rockchip,grf = <&grf>;
+       interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+       clock-names = "iahb", "isfr";
+       status = "disabled";
+       ports {
+               hdmi_in: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       hdmi_in_vopb: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&vopb_out_hdmi>;
+                       };
+                       hdmi_in_vopl: endpoint@1 {
+                               reg = <1>;
+                               remote-endpoint = <&vopl_out_hdmi>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt
new file mode 100644 (file)
index 0000000..5707af8
--- /dev/null
@@ -0,0 +1,19 @@
+Rockchip DRM master device
+================================
+
+The Rockchip DRM master device is a virtual device needed to list all
+vop devices or other display interface nodes that comprise the
+graphics subsystem.
+
+Required properties:
+- compatible: Should be "rockchip,display-subsystem"
+- ports: Should contain a list of phandles pointing to display interface port
+  of vop devices. vop definitions as defined in
+  Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
+
+example:
+
+display-subsystem {
+       compatible = "rockchip,display-subsystem";
+       ports = <&vopl_out>, <&vopb_out>;
+};
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt
new file mode 100644 (file)
index 0000000..d15351f
--- /dev/null
@@ -0,0 +1,58 @@
+device-tree bindings for rockchip soc display controller (vop)
+
+VOP (Visual Output Processor) is the Display Controller for the Rockchip
+series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be one of the following
+               "rockchip,rk3288-vop";
+
+- interrupts: should contain a list of all VOP IP block interrupts in the
+                order: VSYNC, LCD_SYSTEM. The interrupt specifier
+                format depends on the interrupt controller used.
+
+- clocks: must include clock specifiers corresponding to entries in the
+               clock-names property.
+
+- clock-names: Must contain
+               aclk_vop: for ddr buffer transfer.
+               hclk_vop: for ahb bus to R/W the phy regs.
+               dclk_vop: pixel clock.
+
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: Must include the following entries:
+  - axi
+  - ahb
+  - dclk
+
+- iommus: required a iommu node
+
+- port: A port node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+SoC specific DT entry:
+       vopb: vopb@ff930000 {
+               compatible = "rockchip,rk3288-vop";
+               reg = <0xff930000 0x19c>;
+               interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
+               clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+               resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>;
+               reset-names = "axi", "ahb", "dclk";
+               iommus = <&vopb_mmu>;
+               vopb_out: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       vopb_out_edp: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint=<&edp_in_vopb>;
+                       };
+                       vopb_out_hdmi: endpoint@1 {
+                               reg = <1>;
+                               remote-endpoint=<&hdmi_in_vopb>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt
new file mode 100644 (file)
index 0000000..c46ba64
--- /dev/null
@@ -0,0 +1,33 @@
+Sunxi specific Simple Framebuffer bindings
+
+This binding documents sunxi specific extensions to the simple-framebuffer
+bindings. The sunxi simplefb u-boot code relies on the devicetree containing
+pre-populated simplefb nodes.
+
+These extensions are intended so that u-boot can select the right node based
+on which pipeline is being used. As such they are solely intended for
+firmware / bootloader use, and the OS should ignore them.
+
+Required properties:
+- compatible: "allwinner,simple-framebuffer"
+- allwinner,pipeline, one of:
+  "de_be0-lcd0"
+  "de_be1-lcd1"
+  "de_be0-lcd0-hdmi"
+  "de_be1-lcd1-hdmi"
+
+Example:
+
+chosen {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+
+       framebuffer@0 {
+               compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+               allwinner,pipeline = "de_be0-lcd0-hdmi";
+               clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+                        <&ahb_gates 44>;
+               status = "disabled";
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer.txt b/Documentation/devicetree/bindings/display/simple-framebuffer.txt
new file mode 100644 (file)
index 0000000..4474ef6
--- /dev/null
@@ -0,0 +1,86 @@
+Simple Framebuffer
+
+A simple frame-buffer describes a frame-buffer setup by firmware or
+the bootloader, with the assumption that the display hardware has already
+been set up to scan out from the memory pointed to by the reg property.
+
+Since simplefb nodes represent runtime information they must be sub-nodes of
+the chosen node (*). Simplefb nodes must be named "framebuffer@<address>".
+
+If the devicetree contains nodes for the display hardware used by a simplefb,
+then the simplefb node must contain a property called "display", which
+contains a phandle pointing to the primary display hw node, so that the OS
+knows which simplefb to disable when handing over control to a driver for the
+real hardware. The bindings for the hw nodes must specify which node is
+considered the primary node.
+
+It is advised to add display# aliases to help the OS determine how to number
+things. If display# aliases are used, then if the simplefb node contains a
+"display" property then the /aliases/display# path must point to the display
+hw node the "display" property points to, otherwise it must point directly
+to the simplefb node.
+
+If a simplefb node represents the preferred console for user interaction,
+then the chosen node's stdout-path property should point to it, or to the
+primary display hw node, as with display# aliases. If display aliases are
+used then it should be set to the alias instead.
+
+It is advised that devicetree files contain pre-filled, disabled framebuffer
+nodes, so that the firmware only needs to update the mode information and
+enable them. This way if e.g. later on support for more display clocks get
+added, the simplefb nodes will already contain this info and the firmware
+does not need to be updated.
+
+If pre-filled framebuffer nodes are used, the firmware may need extra
+information to find the right node. In that case an extra platform specific
+compatible and platform specific properties should be used and documented,
+see e.g. simple-framebuffer-sunxi.txt .
+
+Required properties:
+- compatible: "simple-framebuffer"
+- reg: Should contain the location and size of the framebuffer memory.
+- width: The width of the framebuffer in pixels.
+- height: The height of the framebuffer in pixels.
+- stride: The number of bytes in each line of the framebuffer.
+- format: The format of the framebuffer surface. Valid values are:
+  - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b).
+  - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
+
+Optional properties:
+- clocks : List of clocks used by the framebuffer. Clocks listed here
+           are expected to already be configured correctly. The OS must
+           ensure these clocks are not modified or disabled while the
+           simple framebuffer remains active.
+- display : phandle pointing to the primary display hardware node
+
+Example:
+
+aliases {
+       display0 = &lcdc0;
+}
+
+chosen {
+       framebuffer0: framebuffer@1d385000 {
+               compatible = "simple-framebuffer";
+               reg = <0x1d385000 (1600 * 1200 * 2)>;
+               width = <1600>;
+               height = <1200>;
+               stride = <(1600 * 2)>;
+               format = "r5g6b5";
+               clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
+               display = <&lcdc0>;
+       };
+       stdout-path = "display0";
+};
+
+soc@01c00000 {
+       lcdc0: lcdc@1c0c000 {
+               compatible = "allwinner,sun4i-a10-lcdc";
+               ...
+       };
+};
+
+
+*) Older devicetree files may have a compatible = "simple-framebuffer" node
+in a different place, operating systems must first enumerate any compatible
+nodes found under chosen and then check for other compatible nodes.
diff --git a/Documentation/devicetree/bindings/display/sm501fb.txt b/Documentation/devicetree/bindings/display/sm501fb.txt
new file mode 100644 (file)
index 0000000..9d9f009
--- /dev/null
@@ -0,0 +1,34 @@
+* SM SM501
+
+The SM SM501 is a LCD controller, with proper hardware, it can also
+drive DVI monitors.
+
+Required properties:
+- compatible : should be "smi,sm501".
+- reg : contain two entries:
+    - First entry: System Configuration register
+    - Second entry: IO space (Display Controller register)
+- interrupts : SMI interrupt to the cpu should be described here.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- mode : select a video mode:
+    <xres>x<yres>[-<bpp>][@<refresh>]
+- edid : verbatim EDID data block describing attached display.
+  Data from the detailed timing descriptor will be used to
+  program the display controller.
+- little-endian: available on big endian systems, to
+  set different foreign endian.
+- big-endian: available on little endian systems, to
+  set different foreign endian.
+
+Example for MPC5200:
+       display@1,0 {
+               compatible = "smi,sm501";
+               reg = <1 0x00000000 0x00800000
+                      1 0x03e00000 0x00200000>;
+               interrupts = <1 1 3>;
+               mode = "640x480-32@60";
+               edid = [edid-data];
+       };
diff --git a/Documentation/devicetree/bindings/display/ssd1289fb.txt b/Documentation/devicetree/bindings/display/ssd1289fb.txt
new file mode 100644 (file)
index 0000000..4fcd5e6
--- /dev/null
@@ -0,0 +1,13 @@
+* Solomon SSD1289 Framebuffer Driver
+
+Required properties:
+  - compatible: Should be "solomon,ssd1289fb". The only supported bus for
+    now is lbc.
+  - reg: Should contain address of the controller on the LBC bus. The detail
+    was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
+
+Examples:
+display@2,0 {
+       compatible = "solomon,ssd1289fb";
+       reg = <0x2 0x0000 0x0004>;
+};
diff --git a/Documentation/devicetree/bindings/display/ssd1307fb.txt b/Documentation/devicetree/bindings/display/ssd1307fb.txt
new file mode 100644 (file)
index 0000000..d1be78d
--- /dev/null
@@ -0,0 +1,49 @@
+* Solomon SSD1307 Framebuffer Driver
+
+Required properties:
+  - compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
+    now is i2c, and the supported chips are ssd1305, ssd1306 and ssd1307.
+  - reg: Should contain address of the controller on the I2C bus. Most likely
+         0x3c or 0x3d
+  - pwm: Should contain the pwm to use according to the OF device tree PWM
+         specification [0]. Only required for the ssd1307.
+  - reset-gpios: Should contain the GPIO used to reset the OLED display
+  - solomon,height: Height in pixel of the screen driven by the controller
+  - solomon,width: Width in pixel of the screen driven by the controller
+  - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is
+    mapped to.
+
+Optional properties:
+  - reset-active-low: Is the reset gpio is active on physical low?
+  - solomon,segment-no-remap: Display needs normal (non-inverted) data column
+                              to segment mapping
+  - solomon,com-seq: Display uses sequential COM pin configuration
+  - solomon,com-lrremap: Display uses left-right COM pin remap
+  - solomon,com-invdir: Display uses inverted COM pin scan direction
+  - solomon,com-offset: Number of the COM pin wired to the first display line
+  - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
+  - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
+                         This needs to be the higher, the higher the capacitance
+                         of the OLED's pixels is
+
+[0]: Documentation/devicetree/bindings/pwm/pwm.txt
+
+Examples:
+ssd1307: oled@3c {
+        compatible = "solomon,ssd1307fb-i2c";
+        reg = <0x3c>;
+        pwms = <&pwm 4 3000>;
+        reset-gpios = <&gpio2 7>;
+        reset-active-low;
+};
+
+ssd1306: oled@3c {
+        compatible = "solomon,ssd1306fb-i2c";
+        reg = <0x3c>;
+        pwms = <&pwm 4 3000>;
+        reset-gpios = <&gpio2 7>;
+        reset-active-low;
+        solomon,com-lrremap;
+        solomon,com-invdir;
+        solomon,com-offset = <32>;
+};
diff --git a/Documentation/devicetree/bindings/display/st,stih4xx.txt b/Documentation/devicetree/bindings/display/st,stih4xx.txt
new file mode 100644 (file)
index 0000000..a352ed3
--- /dev/null
@@ -0,0 +1,241 @@
+STMicroelectronics stih4xx platforms
+
+- sti-vtg: video timing generator
+  Required properties:
+  - compatible: "st,vtg"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  Optional properties:
+  - interrupts : VTG interrupt number to the CPU.
+  - st,slave: phandle on a slave vtg
+
+- sti-vtac: video timing advanced inter dye communication Rx and TX
+  Required properties:
+  - compatible: "st,vtac-main" or "st,vtac-aux"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+
+- sti-display-subsystem: Master device for DRM sub-components
+  This device must be the parent of all the sub-components and is responsible
+  of bind them.
+  Required properties:
+  - compatible: "st,sti-display-subsystem"
+  - ranges: to allow probing of subdevices
+
+- sti-compositor: frame compositor engine
+  must be a child of sti-display-subsystem
+  Required properties:
+  - compatible: "st,stih<chip>-compositor"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+  - resets: resets to be used by the device
+    See ../reset/reset.txt for details.
+  - reset-names: names of the resets listed in resets property in the same
+    order.
+  - st,vtg: phandle(s) on vtg device (main and aux) nodes.
+
+- sti-tvout: video out hardware block
+  must be a child of sti-display-subsystem
+  Required properties:
+  - compatible: "st,stih<chip>-tvout"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - reg-names: names of the mapped memory regions listed in regs property in
+    the same order.
+  - resets: resets to be used by the device
+    See ../reset/reset.txt for details.
+  - reset-names: names of the resets listed in resets property in the same
+    order.
+
+- sti-hdmi: hdmi output block
+  must be a child of sti-display-subsystem
+  Required properties:
+  - compatible: "st,stih<chip>-hdmi";
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - reg-names: names of the mapped memory regions listed in regs property in
+    the same order.
+  - interrupts : HDMI interrupt number to the CPU.
+  - interrupt-names: names of the interrupts listed in interrupts property in
+    the same order
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+  - ddc: phandle of an I2C controller used for DDC EDID probing
+
+sti-hda:
+  Required properties:
+  must be a child of sti-display-subsystem
+  - compatible: "st,stih<chip>-hda"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - reg-names: names of the mapped memory regions listed in regs property in
+    the same order.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+
+sti-dvo:
+  Required properties:
+  must be a child of sti-display-subsystem
+  - compatible: "st,stih<chip>-dvo"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - reg-names: names of the mapped memory regions listed in regs property in
+    the same order.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+  - pinctrl-0: pin control handle
+  - pinctrl-names: names of the pin control states to use
+  - sti,panel: phandle of the panel connected to the DVO output
+
+sti-hqvdp:
+  must be a child of sti-display-subsystem
+  Required properties:
+  - compatible: "st,stih<chip>-hqvdp"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+  - resets: resets to be used by the device
+    See ../reset/reset.txt for details.
+  - reset-names: names of the resets listed in resets property in the same
+    order.
+  - st,vtg: phandle on vtg main device node.
+
+Example:
+
+/ {
+       ...
+
+       vtg_main_slave: sti-vtg-main-slave@fe85A800 {
+               compatible      = "st,vtg";
+               reg             = <0xfe85A800 0x300>;
+               interrupts      = <GIC_SPI 175 IRQ_TYPE_NONE>;
+       };
+
+       vtg_main: sti-vtg-main-master@fd348000 {
+               compatible      = "st,vtg";
+               reg             = <0xfd348000 0x400>;
+               st,slave        = <&vtg_main_slave>;
+       };
+
+       vtg_aux_slave: sti-vtg-aux-slave@fd348400 {
+               compatible      = "st,vtg";
+               reg             = <0xfe858200 0x300>;
+               interrupts      = <GIC_SPI 176 IRQ_TYPE_NONE>;
+       };
+
+       vtg_aux: sti-vtg-aux-master@fd348400 {
+               compatible      = "st,vtg";
+               reg             = <0xfd348400 0x400>;
+               st,slave        = <&vtg_aux_slave>;
+       };
+
+
+       sti-vtac-rx-main@fee82800 {
+               compatible      = "st,vtac-main";
+               reg             = <0xfee82800 0x200>;
+               clock-names     = "vtac";
+               clocks          = <&clk_m_a2_div0 CLK_M_VTAC_MAIN_PHY>;
+       };
+
+       sti-vtac-rx-aux@fee82a00 {
+               compatible      = "st,vtac-aux";
+               reg             = <0xfee82a00 0x200>;
+               clock-names     = "vtac";
+               clocks          = <&clk_m_a2_div0 CLK_M_VTAC_AUX_PHY>;
+       };
+
+       sti-vtac-tx-main@fd349000 {
+               compatible      = "st,vtac-main";
+               reg             = <0xfd349000 0x200>, <0xfd320000 0x10000>;
+               clock-names     = "vtac";
+               clocks           = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
+       };
+
+       sti-vtac-tx-aux@fd349200 {
+               compatible      = "st,vtac-aux";
+               reg             = <0xfd349200 0x200>, <0xfd320000 0x10000>;
+               clock-names     = "vtac";
+               clocks          = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
+       };
+
+       sti-display-subsystem {
+               compatible = "st,sti-display-subsystem";
+               ranges;
+
+               sti-compositor@fd340000 {
+                       compatible      = "st,stih416-compositor";
+                       reg             = <0xfd340000 0x1000>;
+                       clock-names     = "compo_main", "compo_aux",
+                                         "pix_main", "pix_aux";
+                       clocks          = <&clk_m_a2_div1 CLK_M_COMPO_MAIN>, <&clk_m_a2_div1 CLK_M_COMPO_AUX>,
+                                         <&clockgen_c_vcc CLK_S_PIX_MAIN>, <&clockgen_c_vcc CLK_S_PIX_AUX>;
+                       reset-names     = "compo-main", "compo-aux";
+                       resets          = <&softreset STIH416_COMPO_M_SOFTRESET>, <&softreset STIH416_COMPO_A_SOFTRESET>;
+                       st,vtg          = <&vtg_main>, <&vtg_aux>;
+               };
+
+               sti-tvout@fe000000 {
+                       compatible      = "st,stih416-tvout";
+                       reg             = <0xfe000000 0x1000>, <0xfe85a000 0x400>, <0xfe830000 0x10000>;
+                       reg-names       = "tvout-reg", "hda-reg", "syscfg";
+                       reset-names     = "tvout";
+                       resets          = <&softreset STIH416_HDTVOUT_SOFTRESET>;
+               };
+
+               sti-hdmi@fe85c000 {
+                       compatible      = "st,stih416-hdmi";
+                       reg             = <0xfe85c000 0x1000>, <0xfe830000 0x10000>;
+                       reg-names       = "hdmi-reg", "syscfg";
+                       interrupts      = <GIC_SPI 173 IRQ_TYPE_NONE>;
+                       interrupt-names = "irq";
+                       clock-names     = "pix", "tmds", "phy", "audio";
+                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>;
+               };
+
+               sti-hda@fe85a000 {
+                       compatible      = "st,stih416-hda";
+                       reg             = <0xfe85a000 0x400>, <0xfe83085c 0x4>;
+                       reg-names       = "hda-reg", "video-dacs-ctrl";
+                       clock-names     = "pix", "hddac";
+                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
+               };
+
+               sti-dvo@8d00400 {
+                       compatible      = "st,stih407-dvo";
+                       reg             = <0x8d00400 0x200>;
+                       reg-names       = "dvo-reg";
+                       clock-names     = "dvo_pix", "dvo",
+                                         "main_parent", "aux_parent";
+                       clocks          = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
+                                         <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
+                       pinctrl-names   = "default";
+                       pinctrl-0       = <&pinctrl_dvo>;
+                       sti,panel       = <&panel_dvo>;
+               };
+
+               sti-hqvdp@9c000000 {
+                               compatible      = "st,stih407-hqvdp";
+                               reg             = <0x9C00000 0x100000>;
+                               clock-names     = "hqvdp", "pix_main";
+                               clocks          = <&clk_s_c0_flexgen CLK_MAIN_DISP>, <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>;
+                               reset-names     = "hqvdp";
+                               resets          = <&softreset STIH407_HDQVDP_SOFTRESET>;
+                               st,vtg          = <&vtg_main>;
+               };
+       };
+       ...
+};
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra114-mipi.txt
new file mode 100644 (file)
index 0000000..e4a25ce
--- /dev/null
@@ -0,0 +1,41 @@
+NVIDIA Tegra MIPI pad calibration controller
+
+Required properties:
+- compatible: "nvidia,tegra<chip>-mipi"
+- reg: Physical base address and length of the controller's registers.
+- clocks: Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+  - mipi-cal
+- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads
+  that need to be calibrated for a given device.
+
+User nodes need to contain an nvidia,mipi-calibrate property that has a
+phandle to refer to the calibration controller node and a bitmask of the pads
+that need to be calibrated.
+
+Example:
+
+       mipi: mipi@700e3000 {
+               compatible = "nvidia,tegra114-mipi";
+               reg = <0x700e3000 0x100>;
+               clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>;
+               clock-names = "mipi-cal";
+               #nvidia,mipi-calibrate-cells = <1>;
+       };
+
+       ...
+
+       host1x@50000000 {
+               ...
+
+               dsi@54300000 {
+                       ...
+
+                       nvidia,mipi-calibrate = <&mipi 0x060>;
+
+                       ...
+               };
+
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
new file mode 100644 (file)
index 0000000..a3bd8c0
--- /dev/null
@@ -0,0 +1,380 @@
+NVIDIA Tegra host1x
+
+Required properties:
+- compatible: "nvidia,tegra<chip>-host1x"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The interrupt outputs from the controller.
+- #address-cells: The number of cells used to represent physical base addresses
+  in the host1x address space. Should be 1.
+- #size-cells: The number of cells used to represent the size of an address
+  range in the host1x address space. Should be 1.
+- ranges: The mapping of the host1x address space to the CPU address space.
+- clocks: Must contain one entry, for the module clock.
+  See ../clocks/clock-bindings.txt for details.
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: Must include the following entries:
+  - host1x
+
+The host1x top-level node defines a number of children, each representing one
+of the following host1x client modules:
+
+- mpe: video encoder
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-mpe"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - mpe
+
+- vi: video input
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-vi"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - vi
+
+- epp: encoder pre-processor
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-epp"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - epp
+
+- isp: image signal processor
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-isp"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - isp
+
+- gr2d: 2D graphics engine
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-gr2d"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - 2d
+
+- gr3d: 3D graphics engine
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-gr3d"
+  - reg: Physical base address and length of the controller's registers.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    (This property may be omitted if the only clock in the list is "3d")
+    - 3d
+      This MUST be the first entry.
+    - 3d2 (Only required on SoCs with two 3D clocks)
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - 3d
+    - 3d2 (Only required on SoCs with two 3D clocks)
+
+- dc: display controller
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-dc"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - dc
+      This MUST be the first entry.
+    - parent
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - dc
+  - nvidia,head: The number of the display controller head. This is used to
+    setup the various types of output to receive video data from the given
+    head.
+
+  Each display controller node has a child node, named "rgb", that represents
+  the RGB output associated with the controller. It can take the following
+  optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
+
+- hdmi: High Definition Multimedia Interface
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-hdmi"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - hdmi-supply: supply for the +5V HDMI connector pin
+  - vdd-supply: regulator for supply voltage
+  - pll-supply: regulator for PLL
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - hdmi
+      This MUST be the first entry.
+    - parent
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - hdmi
+
+  Optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
+
+- tvo: TV encoder output
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-tvo"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain one entry, for the module clock.
+    See ../clocks/clock-bindings.txt for details.
+
+- dsi: display serial interface
+
+  Required properties:
+  - compatible: "nvidia,tegra<chip>-dsi"
+  - reg: Physical base address and length of the controller's registers.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - dsi
+      This MUST be the first entry.
+    - lp
+    - parent
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - dsi
+  - avdd-dsi-supply: phandle of a supply that powers the DSI controller
+  - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying
+    which pads are used by this DSI output and need to be calibrated. See also
+    ../display/tegra/nvidia,tegra114-mipi.txt.
+
+  Optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
+  - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang
+    up with in order to support up to 8 data lanes
+
+- sor: serial output resource
+
+  Required properties:
+  - compatible: Should be:
+    - "nvidia,tegra124-sor": for Tegra124 and Tegra132
+    - "nvidia,tegra132-sor": for Tegra132
+    - "nvidia,tegra210-sor": for Tegra210
+    - "nvidia,tegra210-sor1": for Tegra210
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - sor: clock input for the SOR hardware
+    - parent: input for the pixel clock
+    - dp: reference clock for the SOR clock
+    - safe: safe reference for the SOR clock during power up
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - sor
+
+  Optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
+
+  Optional properties when driving an eDP output:
+  - nvidia,dpaux: phandle to a DispayPort AUX interface
+
+- dpaux: DisplayPort AUX interface
+  - compatible: For Tegra124, must contain "nvidia,tegra124-dpaux".  Otherwise,
+    must contain '"nvidia,<chip>-dpaux", "nvidia,tegra124-dpaux"', where
+    <chip> is tegra132.
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - dpaux: clock input for the DPAUX hardware
+    - parent: reference clock
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - dpaux
+  - vdd-supply: phandle of a supply that powers the DisplayPort link
+
+Example:
+
+/ {
+       ...
+
+       host1x {
+               compatible = "nvidia,tegra20-host1x", "simple-bus";
+               reg = <0x50000000 0x00024000>;
+               interrupts = <0 65 0x04   /* mpcore syncpt */
+                             0 67 0x04>; /* mpcore general */
+               clocks = <&tegra_car TEGRA20_CLK_HOST1X>;
+               resets = <&tegra_car 28>;
+               reset-names = "host1x";
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               ranges = <0x54000000 0x54000000 0x04000000>;
+
+               mpe {
+                       compatible = "nvidia,tegra20-mpe";
+                       reg = <0x54040000 0x00040000>;
+                       interrupts = <0 68 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_MPE>;
+                       resets = <&tegra_car 60>;
+                       reset-names = "mpe";
+               };
+
+               vi {
+                       compatible = "nvidia,tegra20-vi";
+                       reg = <0x54080000 0x00040000>;
+                       interrupts = <0 69 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_VI>;
+                       resets = <&tegra_car 100>;
+                       reset-names = "vi";
+               };
+
+               epp {
+                       compatible = "nvidia,tegra20-epp";
+                       reg = <0x540c0000 0x00040000>;
+                       interrupts = <0 70 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_EPP>;
+                       resets = <&tegra_car 19>;
+                       reset-names = "epp";
+               };
+
+               isp {
+                       compatible = "nvidia,tegra20-isp";
+                       reg = <0x54100000 0x00040000>;
+                       interrupts = <0 71 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_ISP>;
+                       resets = <&tegra_car 23>;
+                       reset-names = "isp";
+               };
+
+               gr2d {
+                       compatible = "nvidia,tegra20-gr2d";
+                       reg = <0x54140000 0x00040000>;
+                       interrupts = <0 72 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_GR2D>;
+                       resets = <&tegra_car 21>;
+                       reset-names = "2d";
+               };
+
+               gr3d {
+                       compatible = "nvidia,tegra20-gr3d";
+                       reg = <0x54180000 0x00040000>;
+                       clocks = <&tegra_car TEGRA20_CLK_GR3D>;
+                       resets = <&tegra_car 24>;
+                       reset-names = "3d";
+               };
+
+               dc@54200000 {
+                       compatible = "nvidia,tegra20-dc";
+                       reg = <0x54200000 0x00040000>;
+                       interrupts = <0 73 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_DISP1>,
+                                <&tegra_car TEGRA20_CLK_PLL_P>;
+                       clock-names = "dc", "parent";
+                       resets = <&tegra_car 27>;
+                       reset-names = "dc";
+
+                       rgb {
+                               status = "disabled";
+                       };
+               };
+
+               dc@54240000 {
+                       compatible = "nvidia,tegra20-dc";
+                       reg = <0x54240000 0x00040000>;
+                       interrupts = <0 74 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_DISP2>,
+                                <&tegra_car TEGRA20_CLK_PLL_P>;
+                       clock-names = "dc", "parent";
+                       resets = <&tegra_car 26>;
+                       reset-names = "dc";
+
+                       rgb {
+                               status = "disabled";
+                       };
+               };
+
+               hdmi {
+                       compatible = "nvidia,tegra20-hdmi";
+                       reg = <0x54280000 0x00040000>;
+                       interrupts = <0 75 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_HDMI>,
+                                <&tegra_car TEGRA20_CLK_PLL_D_OUT0>;
+                       clock-names = "hdmi", "parent";
+                       resets = <&tegra_car 51>;
+                       reset-names = "hdmi";
+                       status = "disabled";
+               };
+
+               tvo {
+                       compatible = "nvidia,tegra20-tvo";
+                       reg = <0x542c0000 0x00040000>;
+                       interrupts = <0 76 0x04>;
+                       clocks = <&tegra_car TEGRA20_CLK_TVO>;
+                       status = "disabled";
+               };
+
+               dsi {
+                       compatible = "nvidia,tegra20-dsi";
+                       reg = <0x54300000 0x00040000>;
+                       clocks = <&tegra_car TEGRA20_CLK_DSI>,
+                                <&tegra_car TEGRA20_CLK_PLL_D_OUT0>;
+                       clock-names = "dsi", "parent";
+                       resets = <&tegra_car 48>;
+                       reset-names = "dsi";
+                       status = "disabled";
+               };
+       };
+
+       ...
+};
diff --git a/Documentation/devicetree/bindings/display/ti/ti,dra7-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,dra7-dss.txt
new file mode 100644 (file)
index 0000000..c30f9ec
--- /dev/null
@@ -0,0 +1,69 @@
+Texas Instruments DRA7x Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,dra7-dss"
+- reg: address and length of the register spaces for 'dss'
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+- syscon: phandle to control module core syscon node
+
+Optional properties:
+
+Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties
+can be used to describe the video PLLs:
+
+- reg: address and length of the register spaces for 'pll1_clkctrl',
+  'pll1', 'pll2_clkctrl', 'pll2'
+- clocks: handle to video1 pll clock and video2 pll clock
+- clock-names: "video1_clk" and "video2_clk"
+
+Required nodes:
+- DISPC
+
+Optional nodes:
+- DSS Submodules: HDMI
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,dra7-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+HDMI
+----
+
+Required properties:
+- compatible: "ti,dra7-hdmi"
+- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
+       'core'
+- reg-names: "wp", "pll", "phy", "core"
+- interrupts: the HDMI interrupt line
+- ti,hwmods: "dss_hdmi"
+- vdda-supply: vdda power supply
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for HDMI output
+
+HDMI Endpoint optional properties:
+- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
+  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt
new file mode 100644 (file)
index 0000000..e1ef295
--- /dev/null
@@ -0,0 +1,211 @@
+Texas Instruments OMAP Display Subsystem
+========================================
+
+Generic Description
+-------------------
+
+This document is a generic description of the OMAP Display Subsystem bindings.
+Binding details for each OMAP SoC version are described in respective binding
+documentation.
+
+The OMAP Display Subsystem (DSS) hardware consists of DSS Core, DISPC module and
+a number of encoder modules. All DSS versions contain DSS Core and DISPC, but
+the encoder modules vary.
+
+The DSS Core is the parent of the other DSS modules, and manages clock routing,
+integration to the SoC, etc.
+
+DISPC is the display controller, which reads pixels from the memory and outputs
+a RGB pixel stream to encoders.
+
+The encoder modules encode the received RGB pixel stream to a video output like
+HDMI, MIPI DPI, etc.
+
+Video Ports
+-----------
+
+The DSS Core and the encoders have video port outputs. The structure of the
+video ports is described in Documentation/devicetree/bindings/graph.txt,
+and the properties for the ports and endpoints for each encoder are
+described in the SoC's DSS binding documentation.
+
+The video ports are used to describe the connections to external hardware, like
+panels or external encoders.
+
+Aliases
+-------
+
+The board dts file may define aliases for displays to assign "displayX" style
+name for each display. If no aliases are defined, a semi-random number is used
+for the display.
+
+Example
+-------
+
+A shortened example of the DSS description for OMAP4, with non-relevant parts
+removed, defined in omap4.dtsi:
+
+dss: dss@58000000 {
+       compatible = "ti,omap4-dss";
+       reg = <0x58000000 0x80>;
+       status = "disabled";
+       ti,hwmods = "dss_core";
+       clocks = <&dss_dss_clk>;
+       clock-names = "fck";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+
+       dispc@58001000 {
+               compatible = "ti,omap4-dispc";
+               reg = <0x58001000 0x1000>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               ti,hwmods = "dss_dispc";
+               clocks = <&dss_dss_clk>;
+               clock-names = "fck";
+       };
+
+       hdmi: encoder@58006000 {
+               compatible = "ti,omap4-hdmi";
+               reg = <0x58006000 0x200>,
+                     <0x58006200 0x100>,
+                     <0x58006300 0x100>,
+                     <0x58006400 0x1000>;
+               reg-names = "wp", "pll", "phy", "core";
+               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+               status = "disabled";
+               ti,hwmods = "dss_hdmi";
+               clocks = <&dss_48mhz_clk>, <&dss_sys_clk>;
+               clock-names = "fck", "sys_clk";
+       };
+};
+
+A shortened example of the board description for OMAP4 Panda board, defined in
+omap4-panda.dts.
+
+The Panda board has a DVI and a HDMI connector, and the board contains a TFP410
+chip (MIPI DPI to DVI encoder) and a TPD12S015 chip (HDMI ESD protection & level
+shifter). The video pipelines for the connectors are formed as follows:
+
+DSS Core --(MIPI DPI)--> TFP410 --(DVI)--> DVI Connector
+OMAP HDMI --(HDMI)--> TPD12S015 --(HDMI)--> HDMI Connector
+
+/ {
+       aliases {
+               display0 = &dvi0;
+               display1 = &hdmi0;
+       };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;     /* 0, power-down */
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tfp410_pins>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
+
+       tpd12s015: encoder@1 {
+               compatible = "ti,tpd12s015";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tpd12s015_pins>;
+
+               gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+                       <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+                       <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tpd12s015_in: endpoint@0 {
+                                       remote-endpoint = <&hdmi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tpd12s015_out: endpoint@0 {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       hdmi0: connector@1 {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&tpd12s015_out>;
+                       };
+               };
+       };
+};
+
+&dss {
+       status = "ok";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_dpi_pins>;
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
+
+&hdmi {
+       status = "ok";
+       vdda-supply = <&vdac>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_hdmi_pins>;
+
+       port {
+               hdmi_out: endpoint {
+                       remote-endpoint = <&tpd12s015_in>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap2-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap2-dss.txt
new file mode 100644 (file)
index 0000000..afcd5a8
--- /dev/null
@@ -0,0 +1,54 @@
+Texas Instruments OMAP2 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap2-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+
+Optional nodes:
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap2-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap2-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap2-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+
+VENC Endpoint required properties:
+
+Required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap3-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap3-dss.txt
new file mode 100644 (file)
index 0000000..dc66e14
--- /dev/null
@@ -0,0 +1,83 @@
+Texas Instruments OMAP3 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap3-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Optional nodes:
+- Video ports:
+       - Port 0: DPI output
+       - Port 1: SDI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+SDI Endpoint required properties:
+- datapairs: number of datapairs used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap3-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap3-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+- clocks: handles to fclk and iclk
+- clock-names: "fck", "ick"
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap3-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+- clocks: handle to fclk
+- clock-names: "fck"
+
+VENC Endpoint required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
+
+
+DSI
+---
+
+Required properties:
+- compatible: "ti,omap3-dsi"
+- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
+- reg-names: "proto", "phy", "pll"
+- interrupts: the DSI interrupt line
+- ti,hwmods: "dss_dsi1"
+- vdd-supply: power supply for DSI
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+DSI Endpoint required properties:
+- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
+  DATA1+, DATA1-, ...
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap4-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap4-dss.txt
new file mode 100644 (file)
index 0000000..bc624db
--- /dev/null
@@ -0,0 +1,115 @@
+Texas Instruments OMAP4 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap4-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Required nodes:
+- DISPC
+
+Optional nodes:
+- DSS Submodules: RFBI, VENC, DSI, HDMI
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap4-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap4-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+- clocks: handles to fclk and iclk
+- clock-names: "fck", "ick"
+
+Optional nodes:
+- Video port for RFBI output
+- RFBI controlled peripherals
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap4-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Optional nodes:
+- Video port for VENC output
+
+VENC Endpoint required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
+
+
+DSI
+---
+
+Required properties:
+- compatible: "ti,omap4-dsi"
+- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
+- reg-names: "proto", "phy", "pll"
+- interrupts: the DSI interrupt line
+- ti,hwmods: "dss_dsi1" or "dss_dsi2"
+- vdd-supply: power supply for DSI
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for DSI output
+- DSI controlled peripherals
+
+DSI Endpoint required properties:
+- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
+  DATA1+, DATA1-, ...
+
+
+HDMI
+----
+
+Required properties:
+- compatible: "ti,omap4-hdmi"
+- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
+       'core'
+- reg-names: "wp", "pll", "phy", "core"
+- interrupts: the HDMI interrupt line
+- ti,hwmods: "dss_hdmi"
+- vdda-supply: vdda power supply
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for HDMI output
+
+HDMI Endpoint optional properties:
+- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
+  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
new file mode 100644 (file)
index 0000000..118a486
--- /dev/null
@@ -0,0 +1,96 @@
+Texas Instruments OMAP5 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap5-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Required nodes:
+- DISPC
+
+Optional nodes:
+- DSS Submodules: RFBI, DSI, HDMI
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap5-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap5-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+- clocks: handles to fclk and iclk
+- clock-names: "fck", "ick"
+
+Optional nodes:
+- Video port for RFBI output
+- RFBI controlled peripherals
+
+
+DSI
+---
+
+Required properties:
+- compatible: "ti,omap5-dsi"
+- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
+- reg-names: "proto", "phy", "pll"
+- interrupts: the DSI interrupt line
+- ti,hwmods: "dss_dsi1" or "dss_dsi2"
+- vdd-supply: power supply for DSI
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for DSI output
+- DSI controlled peripherals
+
+DSI Endpoint required properties:
+- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
+  DATA1+, DATA1-, ...
+
+
+HDMI
+----
+
+Required properties:
+- compatible: "ti,omap5-hdmi"
+- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
+       'core'
+- reg-names: "wp", "pll", "phy", "core"
+- interrupts: the HDMI interrupt line
+- ti,hwmods: "dss_hdmi"
+- vdda-supply: vdda power supply
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for HDMI output
+
+HDMI Endpoint optional properties:
+- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
+  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,opa362.txt b/Documentation/devicetree/bindings/display/ti/ti,opa362.txt
new file mode 100644 (file)
index 0000000..f96083c
--- /dev/null
@@ -0,0 +1,38 @@
+OPA362 analog video amplifier
+
+Required properties:
+- compatible: "ti,opa362"
+- enable-gpios: enable/disable output gpio
+
+Required node:
+- Video port 0 for opa362 input
+- Video port 1 for opa362 output
+
+Example:
+
+tv_amp: opa362 {
+       compatible = "ti,opa362";
+       enable-gpios = <&gpio1 23 0>;  /* GPIO to enable video out amplifier */
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       opa_in: endpoint@0 {
+                               remote-endpoint = <&venc_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+                       opa_out: endpoint@0 {
+                               remote-endpoint = <&tv_connector_in>;
+                       };
+               };
+       };
+};
+
+
+
diff --git a/Documentation/devicetree/bindings/display/ti/ti,tfp410.txt b/Documentation/devicetree/bindings/display/ti/ti,tfp410.txt
new file mode 100644 (file)
index 0000000..2cbe32a
--- /dev/null
@@ -0,0 +1,41 @@
+TFP410 DPI to DVI encoder
+=========================
+
+Required properties:
+- compatible: "ti,tfp410"
+
+Optional properties:
+- powerdown-gpios: power-down gpio
+
+Required nodes:
+- Video port 0 for DPI input
+- Video port 1 for DVI output
+
+Example
+-------
+
+tfp410: encoder@0 {
+       compatible = "ti,tfp410";
+       powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       tfp410_in: endpoint@0 {
+                               remote-endpoint = <&dpi_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       tfp410_out: endpoint@0 {
+                               remote-endpoint = <&dvi_connector_in>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/ti/ti,tpd12s015.txt b/Documentation/devicetree/bindings/display/ti/ti,tpd12s015.txt
new file mode 100644 (file)
index 0000000..26e6d32
--- /dev/null
@@ -0,0 +1,44 @@
+TPD12S015 HDMI level shifter and ESD protection chip
+====================================================
+
+Required properties:
+- compatible: "ti,tpd12s015"
+
+Optional properties:
+- gpios: CT CP HPD, LS OE and HPD gpios
+
+Required nodes:
+- Video port 0 for HDMI input
+- Video port 1 for HDMI output
+
+Example
+-------
+
+tpd12s015: encoder@1 {
+       compatible = "ti,tpd12s015";
+
+       gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+               <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+               <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       tpd12s015_in: endpoint@0 {
+                               remote-endpoint = <&hdmi_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       tpd12s015_out: endpoint@0 {
+                               remote-endpoint = <&hdmi_connector_in>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/display/tilcdc/panel.txt b/Documentation/devicetree/bindings/display/tilcdc/panel.txt
new file mode 100644 (file)
index 0000000..f20b31c
--- /dev/null
@@ -0,0 +1,66 @@
+Device-Tree bindings for tilcdc DRM generic panel output driver
+
+Required properties:
+ - compatible: value should be "ti,tilcdc,panel".
+ - panel-info: configuration info to configure LCDC correctly for the panel
+   - ac-bias: AC Bias Pin Frequency
+   - ac-bias-intrpt: AC Bias Pin Transitions per Interrupt
+   - dma-burst-sz: DMA burst size
+   - bpp: Bits per pixel
+   - fdd: FIFO DMA Request Delay
+   - sync-edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
+   - sync-ctrl: Horizontal and Vertical Sync: Control: 0=ignore
+   - raster-order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
+   - fifo-th: DMA FIFO threshold
+ - display-timings: typical videomode of lcd panel.  Multiple video modes
+   can be listed if the panel supports multiple timings, but the 'native-mode'
+   should be the preferred/default resolution.  Refer to
+   Documentation/devicetree/bindings/display/display-timing.txt for display
+   timing binding details.
+
+Optional properties:
+- backlight: phandle of the backlight device attached to the panel
+- enable-gpios: GPIO pin to enable or disable the panel
+
+Recommended properties:
+ - pinctrl-names, pinctrl-0: the pincontrol settings to configure
+   muxing properly for pins that connect to TFP410 device
+
+Example:
+
+       /* Settings for CDTech_S035Q01 / LCD3 cape: */
+       lcd3 {
+               compatible = "ti,tilcdc,panel";
+               pinctrl-names = "default";
+               pinctrl-0 = <&bone_lcd3_cape_lcd_pins>;
+               backlight = <&backlight>;
+               enable-gpios = <&gpio3 19 0>;
+
+               panel-info {
+                       ac-bias           = <255>;
+                       ac-bias-intrpt    = <0>;
+                       dma-burst-sz      = <16>;
+                       bpp               = <16>;
+                       fdd               = <0x80>;
+                       sync-edge         = <0>;
+                       sync-ctrl         = <1>;
+                       raster-order      = <0>;
+                       fifo-th           = <0>;
+               };
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: 320x240 {
+                               hactive         = <320>;
+                               vactive         = <240>;
+                               hback-porch     = <21>;
+                               hfront-porch    = <58>;
+                               hsync-len       = <47>;
+                               vback-porch     = <11>;
+                               vfront-porch    = <23>;
+                               vsync-len       = <2>;
+                               clock-frequency = <8000000>;
+                               hsync-active    = <0>;
+                               vsync-active    = <0>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/tilcdc/tfp410.txt b/Documentation/devicetree/bindings/display/tilcdc/tfp410.txt
new file mode 100644 (file)
index 0000000..a58ae77
--- /dev/null
@@ -0,0 +1,21 @@
+Device-Tree bindings for tilcdc DRM TFP410 output driver
+
+Required properties:
+ - compatible: value should be "ti,tilcdc,tfp410".
+ - i2c: the phandle for the i2c device to use for DDC
+
+Recommended properties:
+ - pinctrl-names, pinctrl-0: the pincontrol settings to configure
+   muxing properly for pins that connect to TFP410 device
+ - powerdn-gpio: the powerdown GPIO, pulled low to power down the
+   TFP410 device (for DPMS_OFF)
+
+Example:
+
+       dvicape {
+               compatible = "ti,tilcdc,tfp410";
+               i2c = <&i2c2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>;
+               powerdn-gpio = <&gpio2 31 0>;
+       };
diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
new file mode 100644 (file)
index 0000000..2136ee8
--- /dev/null
@@ -0,0 +1,56 @@
+Device-Tree bindings for tilcdc DRM driver
+
+Required properties:
+ - compatible: value should be "ti,am33xx-tilcdc".
+ - interrupts: the interrupt number
+ - reg: base address and size of the LCDC device
+
+Recommended properties:
+ - interrupt-parent: the phandle for the interrupt controller that
+   services interrupts for this device.
+ - ti,hwmods: Name of the hwmod associated to the LCDC
+
+Optional properties:
+ - max-bandwidth: The maximum pixels per second that the memory
+   interface / lcd controller combination can sustain
+ - max-width: The maximum horizontal pixel width supported by
+   the lcd controller.
+ - max-pixelclock: The maximum pixel clock that can be supported
+   by the lcd controller in KHz.
+
+Optional nodes:
+
+ - port/ports: to describe a connection to an external encoder. The
+   binding follows Documentation/devicetree/bindings/graph.txt and
+   suppors a single port with a single endpoint.
+
+Example:
+
+       fb: fb@4830e000 {
+               compatible = "ti,am33xx-tilcdc";
+               reg = <0x4830e000 0x1000>;
+               interrupt-parent = <&intc>;
+               interrupts = <36>;
+               ti,hwmods = "lcdc";
+
+               port {
+                       lcdc_0: endpoint@0 {
+                               remote-endpoint = <&hdmi_0>;
+                       };
+               };
+       };
+
+       tda19988: tda19988 {
+               compatible = "nxp,tda998x";
+               reg = <0x70>;
+
+               pinctrl-names = "default", "off";
+               pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+               pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+               port {
+                       hdmi_0: endpoint@0 {
+                               remote-endpoint = <&lcdc_0>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/display/via,vt8500-fb.txt b/Documentation/devicetree/bindings/display/via,vt8500-fb.txt
new file mode 100644 (file)
index 0000000..2871e21
--- /dev/null
@@ -0,0 +1,36 @@
+VIA VT8500 Framebuffer
+-----------------------------------------------------
+
+Required properties:
+- compatible : "via,vt8500-fb"
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : framebuffer controller interrupt
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
+
+Required subnodes:
+- display-timings: see display-timing.txt for information
+
+Example:
+
+       fb@d8050800 {
+               compatible = "via,vt8500-fb";
+               reg = <0xd800e400 0x400>;
+               interrupts = <12>;
+               bits-per-pixel = <16>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: 800x480 {
+                               clock-frequency = <0>; /* unused but required */
+                               hactive = <800>;
+                               vactive = <480>;
+                               hfront-porch = <40>;
+                               hback-porch = <88>;
+                               hsync-len = <0>;
+                               vback-porch = <32>;
+                               vfront-porch = <11>;
+                               vsync-len = <1>;
+                       };
+               };
+       };
+
diff --git a/Documentation/devicetree/bindings/display/wm,prizm-ge-rops.txt b/Documentation/devicetree/bindings/display/wm,prizm-ge-rops.txt
new file mode 100644 (file)
index 0000000..a850fa0
--- /dev/null
@@ -0,0 +1,13 @@
+VIA/Wondermedia Graphics Engine Controller
+-----------------------------------------------------
+
+Required properties:
+- compatible : "wm,prizm-ge-rops"
+- reg : Should contain 1 register ranges(address and length)
+
+Example:
+
+       ge_rops@d8050400 {
+               compatible = "wm,prizm-ge-rops";
+               reg = <0xd8050400 0x100>;
+       };
diff --git a/Documentation/devicetree/bindings/display/wm,wm8505-fb.txt b/Documentation/devicetree/bindings/display/wm,wm8505-fb.txt
new file mode 100644 (file)
index 0000000..0bcadb2
--- /dev/null
@@ -0,0 +1,33 @@
+Wondermedia WM8505 Framebuffer
+-----------------------------------------------------
+
+Required properties:
+- compatible : "wm,wm8505-fb"
+- reg : Should contain 1 register ranges(address and length)
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
+
+Required subnodes:
+- display-timings: see display-timing.txt for information
+
+Example:
+
+       fb@d8051700 {
+               compatible = "wm,wm8505-fb";
+               reg = <0xd8051700 0x200>;
+               bits-per-pixel = <16>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: 800x480 {
+                               clock-frequency = <0>; /* unused but required */
+                               hactive = <800>;
+                               vactive = <480>;
+                               hfront-porch = <40>;
+                               hback-porch = <88>;
+                               hsync-len = <0>;
+                               vback-porch = <32>;
+                               vfront-porch = <11>;
+                               vsync-len = <1>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt b/Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt
deleted file mode 100644 (file)
index 46525ea..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Device Tree bindings for Armada DRM CRTC driver
-
-Required properties:
- - compatible: value should be "marvell,dove-lcd".
- - reg: base address and size of the LCD controller
- - interrupts: single interrupt number for the LCD controller
- - port: video output port with endpoints, as described by graph.txt
-
-Optional properties:
-
- - clocks: as described by clock-bindings.txt
- - clock-names: as described by clock-bindings.txt
-       "axiclk" - axi bus clock for pixel clock
-       "plldivider" - pll divider clock for pixel clock
-       "ext_ref_clk0" - external clock 0 for pixel clock
-       "ext_ref_clk1" - external clock 1 for pixel clock
-
-Note: all clocks are optional but at least one must be specified.
-Further clocks may be added in the future according to requirements of
-different SoCs.
-
-Example:
-
-       lcd0: lcd-controller@820000 {
-               compatible = "marvell,dove-lcd";
-               reg = <0x820000 0x1000>;
-               interrupts = <47>;
-               clocks = <&si5351 0>;
-               clock-names = "ext_ref_clk_1";
-       };
diff --git a/Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt
deleted file mode 100644 (file)
index ebc1a91..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
-
-The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
-See ../mfd/atmel-hlcdc.txt for more details.
-
-Required properties:
- - compatible: value should be "atmel,hlcdc-display-controller"
- - pinctrl-names: the pin control state names. Should contain "default".
- - pinctrl-0: should contain the default pinctrl states.
- - #address-cells: should be set to 1.
- - #size-cells: should be set to 0.
-
-Required children nodes:
- Children nodes are encoding available output ports and their connections
- to external devices using the OF graph reprensentation (see ../graph.txt).
- At least one port node is required.
-
-Example:
-
-       hlcdc: hlcdc@f0030000 {
-               compatible = "atmel,sama5d3-hlcdc";
-               reg = <0xf0030000 0x2000>;
-               interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
-               clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
-               clock-names = "periph_clk","sys_clk", "slow_clk";
-               status = "disabled";
-
-               hlcdc-display-controller {
-                       compatible = "atmel,hlcdc-display-controller";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               reg = <0>;
-
-                               hlcdc_panel_output: endpoint@0 {
-                                       reg = <0>;
-                                       remote-endpoint = <&panel_input>;
-                               };
-                       };
-               };
-
-               hlcdc_pwm: hlcdc-pwm {
-                       compatible = "atmel,hlcdc-pwm";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_lcd_pwm>;
-                       #pwm-cells = <3>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
deleted file mode 100644 (file)
index a905c14..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-DesignWare HDMI bridge bindings
-
-Required properties:
-- compatible: platform specific such as:
-   * "snps,dw-hdmi-tx"
-   * "fsl,imx6q-hdmi"
-   * "fsl,imx6dl-hdmi"
-   * "rockchip,rk3288-dw-hdmi"
-- reg: Physical base address and length of the controller's registers.
-- interrupts: The HDMI interrupt number
-- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
-  as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
-  the clocks are soc specific, the clock-names should be "iahb", "isfr"
--port@[X]: SoC specific port nodes with endpoint definitions as defined
-   in Documentation/devicetree/bindings/media/video-interfaces.txt,
-   please refer to the SoC specific binding document:
-    * Documentation/devicetree/bindings/drm/imx/hdmi.txt
-    * Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
-
-Optional properties
-- reg-io-width: the width of the reg:1,4, default set to 1 if not present
-- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
-
-Example:
-       hdmi: hdmi@0120000 {
-               compatible = "fsl,imx6q-hdmi";
-               reg = <0x00120000 0x9000>;
-               interrupts = <0 115 0x04>;
-               gpr = <&gpr>;
-               clocks = <&clks 123>, <&clks 124>;
-               clock-names = "iahb", "isfr";
-               ddc-i2c-bus = <&i2c2>;
-
-               port@0 {
-                       reg = <0>;
-
-                       hdmi_mux_0: endpoint {
-                               remote-endpoint = <&ipu1_di0_hdmi>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       hdmi_mux_1: endpoint {
-                               remote-endpoint = <&ipu1_di1_hdmi>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt
deleted file mode 100644 (file)
index e9e4bce..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Device-Tree bindings for the NXP TDA998x HDMI transmitter
-
-Required properties;
-  - compatible: must be "nxp,tda998x"
-
-  - reg: I2C address
-
-Optional properties:
-  - interrupts: interrupt number and trigger type
-       default: polling
-
-  - pinctrl-0: pin control group to be used for
-       screen plug/unplug interrupt.
-
-  - pinctrl-names: must contain a "default" entry.
-
-  - video-ports: 24 bits value which defines how the video controller
-       output is wired to the TDA998x input - default: <0x230145>
-
-Example:
-
-       tda998x: hdmi-encoder {
-               compatible = "nxp,tda998x";
-               reg = <0x70>;
-               interrupt-parent = <&gpio0>;
-               interrupts = <27 2>;            /* falling edge */
-               pinctrl-0 = <&pmx_camera>;
-               pinctrl-names = "default";
-       };
diff --git a/Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt b/Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt
deleted file mode 100644 (file)
index 971c3ee..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-Freescale i.MX DRM master device
-================================
-
-The freescale i.MX DRM master device is a virtual device needed to list all
-IPU or other display interface nodes that comprise the graphics subsystem.
-
-Required properties:
-- compatible: Should be "fsl,imx-display-subsystem"
-- ports: Should contain a list of phandles pointing to display interface ports
-  of IPU devices
-
-example:
-
-display-subsystem {
-       compatible = "fsl,display-subsystem";
-       ports = <&ipu_di0>;
-};
-
-
-Freescale i.MX IPUv3
-====================
-
-Required properties:
-- compatible: Should be "fsl,<chip>-ipu"
-- reg: should be register base and length as documented in the
-  datasheet
-- interrupts: Should contain sync interrupt and error interrupt,
-  in this order.
-- resets: phandle pointing to the system reset controller and
-          reset line index, see reset/fsl,imx-src.txt for details
-Optional properties:
-- port@[0-3]: Port nodes with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt.
-  Ports 0 and 1 should correspond to CSI0 and CSI1,
-  ports 2 and 3 should correspond to DI0 and DI1, respectively.
-
-example:
-
-ipu: ipu@18000000 {
-       #address-cells = <1>;
-       #size-cells = <0>;
-       compatible = "fsl,imx53-ipu";
-       reg = <0x18000000 0x080000000>;
-       interrupts = <11 10>;
-       resets = <&src 2>;
-
-       ipu_di0: port@2 {
-               reg = <2>;
-
-               ipu_di0_disp0: endpoint {
-                       remote-endpoint = <&display_in>;
-               };
-       };
-};
-
-Parallel display support
-========================
-
-Required properties:
-- compatible: Should be "fsl,imx-parallel-display"
-Optional properties:
-- interface_pix_fmt: How this display is connected to the
-  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
-  and "lvds666".
-- edid: verbatim EDID data block describing attached display.
-- ddc: phandle describing the i2c bus handling the display data
-  channel
-- port@[0-1]: Port nodes with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt.
-  Port 0 is the input port connected to the IPU display interface,
-  port 1 is the output port connected to a panel.
-
-example:
-
-display@di0 {
-       compatible = "fsl,imx-parallel-display";
-       edid = [edid-data];
-       interface-pix-fmt = "rgb24";
-
-       port@0 {
-               reg = <0>;
-
-               display_in: endpoint {
-                       remote-endpoint = <&ipu_di0_disp0>;
-               };
-       };
-
-       port@1 {
-               reg = <1>;
-
-               display_out: endpoint {
-                       remote-endpoint = <&panel_in>;
-               };
-       };
-};
-
-panel {
-       ...
-
-       port {
-               panel_in: endpoint {
-                       remote-endpoint = <&display_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/drm/imx/hdmi.txt b/Documentation/devicetree/bindings/drm/imx/hdmi.txt
deleted file mode 100644 (file)
index 1b756cf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-Device-Tree bindings for HDMI Transmitter
-
-HDMI Transmitter
-================
-
-The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
-with accompanying PHY IP.
-
-Required properties:
- - #address-cells : should be <1>
- - #size-cells : should be <0>
- - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
- - gpr : should be <&gpr>.
-   The phandle points to the iomuxc-gpr region containing the HDMI
-   multiplexer control register.
- - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
-   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
-   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
- - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
-   Documentation/devicetree/bindings/media/video-interfaces.txt,
-   corresponding to the four inputs to the HDMI multiplexer.
-
-Optional properties:
- - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-
-example:
-
-       gpr: iomuxc-gpr@020e0000 {
-               /* ... */
-       };
-
-        hdmi: hdmi@0120000 {
-                #address-cells = <1>;
-                #size-cells = <0>;
-                compatible = "fsl,imx6q-hdmi";
-                reg = <0x00120000 0x9000>;
-                interrupts = <0 115 0x04>;
-                gpr = <&gpr>;
-                clocks = <&clks 123>, <&clks 124>;
-                clock-names = "iahb", "isfr";
-                ddc-i2c-bus = <&i2c2>;
-
-                port@0 {
-                        reg = <0>;
-
-                        hdmi_mux_0: endpoint {
-                                remote-endpoint = <&ipu1_di0_hdmi>;
-                        };
-                };
-
-                port@1 {
-                        reg = <1>;
-
-                        hdmi_mux_1: endpoint {
-                                remote-endpoint = <&ipu1_di1_hdmi>;
-                        };
-                };
-        };
diff --git a/Documentation/devicetree/bindings/drm/imx/ldb.txt b/Documentation/devicetree/bindings/drm/imx/ldb.txt
deleted file mode 100644 (file)
index 9a21366..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-Device-Tree bindings for LVDS Display Bridge (ldb)
-
-LVDS Display Bridge
-===================
-
-The LVDS Display Bridge device tree node contains up to two lvds-channel
-nodes describing each of the two LVDS encoder channels of the bridge.
-
-Required properties:
- - #address-cells : should be <1>
- - #size-cells : should be <0>
- - compatible : should be "fsl,imx53-ldb" or "fsl,imx6q-ldb".
-                Both LDB versions are similar, but i.MX6 has an additional
-                multiplexer in the front to select any of the four IPU display
-                interfaces as input for each LVDS channel.
- - gpr : should be <&gpr> on i.MX53 and i.MX6q.
-         The phandle points to the iomuxc-gpr region containing the LVDS
-         control register.
-- clocks, clock-names : phandles to the LDB divider and selector clocks and to
-                        the display interface selector clocks, as described in
-                        Documentation/devicetree/bindings/clock/clock-bindings.txt
-        The following clocks are expected on i.MX53:
-                "di0_pll" - LDB LVDS channel 0 mux
-                "di1_pll" - LDB LVDS channel 1 mux
-                "di0" - LDB LVDS channel 0 gate
-                "di1" - LDB LVDS channel 1 gate
-                "di0_sel" - IPU1 DI0 mux
-                "di1_sel" - IPU1 DI1 mux
-        On i.MX6q the following additional clocks are needed:
-                "di2_sel" - IPU2 DI0 mux
-                "di3_sel" - IPU2 DI1 mux
-        The needed clock numbers for each are documented in
-        Documentation/devicetree/bindings/clock/imx5-clock.txt, and in
-        Documentation/devicetree/bindings/clock/imx6q-clock.txt.
-
-Optional properties:
- - pinctrl-names : should be "default" on i.MX53, not used on i.MX6q
- - pinctrl-0 : a phandle pointing to LVDS pin settings on i.MX53,
-               not used on i.MX6q
- - fsl,dual-channel : boolean. if it exists, only LVDS channel 0 should
-   be configured - one input will be distributed on both outputs in dual
-   channel mode
-
-LVDS Channel
-============
-
-Each LVDS Channel has to contain either an of graph link to a panel device node
-or a display-timings node that describes the video timings for the connected
-LVDS display as well as the fsl,data-mapping and fsl,data-width properties.
-
-Required properties:
- - reg : should be <0> or <1>
- - port: Input and output port nodes with endpoint definitions as defined in
-   Documentation/devicetree/bindings/graph.txt.
-   On i.MX5, the internal two-input-multiplexer is used. Due to hardware
-   limitations, only one input port (port@[0,1]) can be used for each channel
-   (lvds-channel@[0,1], respectively).
-   On i.MX6, there should be four input ports (port@[0-3]) that correspond
-   to the four LVDS multiplexer inputs.
-   A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected
-   to a panel input port. Optionally, the output port can be left out if
-   display-timings are used instead.
-
-Optional properties (required if display-timings are used):
- - display-timings : A node that describes the display timings as defined in
-   Documentation/devicetree/bindings/video/display-timing.txt.
- - fsl,data-mapping : should be "spwg" or "jeida"
-                      This describes how the color bits are laid out in the
-                      serialized LVDS signal.
- - fsl,data-width : should be <18> or <24>
-
-example:
-
-gpr: iomuxc-gpr@53fa8000 {
-       /* ... */
-};
-
-ldb: ldb@53fa8008 {
-       #address-cells = <1>;
-       #size-cells = <0>;
-       compatible = "fsl,imx53-ldb";
-       gpr = <&gpr>;
-       clocks = <&clks IMX5_CLK_LDB_DI0_SEL>,
-                <&clks IMX5_CLK_LDB_DI1_SEL>,
-                <&clks IMX5_CLK_IPU_DI0_SEL>,
-                <&clks IMX5_CLK_IPU_DI1_SEL>,
-                <&clks IMX5_CLK_LDB_DI0_GATE>,
-                <&clks IMX5_CLK_LDB_DI1_GATE>;
-       clock-names = "di0_pll", "di1_pll",
-                     "di0_sel", "di1_sel",
-                     "di0", "di1";
-
-       /* Using an of-graph endpoint link to connect the panel */
-       lvds-channel@0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <0>;
-
-               port@0 {
-                       reg = <0>;
-
-                       lvds0_in: endpoint {
-                               remote-endpoint = <&ipu_di0_lvds0>;
-                       };
-               };
-
-               port@2 {
-                       reg = <2>;
-
-                       lvds0_out: endpoint {
-                               remote-endpoint = <&panel_in>;
-                       };
-               };
-       };
-
-       /* Using display-timings and fsl,data-mapping/width instead */
-       lvds-channel@1 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <1>;
-               fsl,data-mapping = "spwg";
-               fsl,data-width = <24>;
-
-               display-timings {
-                       /* ... */
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       lvds1_in: endpoint {
-                               remote-endpoint = <&ipu_di1_lvds1>;
-                       };
-               };
-       };
-};
-
-panel: lvds-panel {
-       /* ... */
-
-       port {
-               panel_in: endpoint {
-                       remote-endpoint = <&lvds0_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/drm/msm/dsi.txt b/Documentation/devicetree/bindings/drm/msm/dsi.txt
deleted file mode 100644 (file)
index d56923c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-Qualcomm Technologies Inc. adreno/snapdragon DSI output
-
-DSI Controller:
-Required properties:
-- compatible:
-  * "qcom,mdss-dsi-ctrl"
-- reg: Physical base address and length of the registers of controller
-- reg-names: The names of register regions. The following regions are required:
-  * "dsi_ctrl"
-- qcom,dsi-host-index: The ID of DSI controller hardware instance. This should
-  be 0 or 1, since we have 2 DSI controllers at most for now.
-- interrupts: The interrupt signal from the DSI block.
-- power-domains: Should be <&mmcc MDSS_GDSC>.
-- clocks: device clocks
-  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
-  * "bus_clk"
-  * "byte_clk"
-  * "core_clk"
-  * "core_mmss_clk"
-  * "iface_clk"
-  * "mdp_core_clk"
-  * "pixel_clk"
-- vdd-supply: phandle to vdd regulator device node
-- vddio-supply: phandle to vdd-io regulator device node
-- vdda-supply: phandle to vdda regulator device node
-- qcom,dsi-phy: phandle to DSI PHY device node
-
-Optional properties:
-- panel@0: Node of panel connected to this DSI controller.
-  See files in Documentation/devicetree/bindings/panel/ for each supported
-  panel.
-- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is
-  driving a panel which needs 2 DSI links.
-- qcom,master-dsi: Boolean value indicating if the DSI controller is driving
-  the master link of the 2-DSI panel.
-- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is
-  driving a 2-DSI panel whose 2 links need receive command simultaneously.
-- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
-  through MDP block
-- pinctrl-names: the pin control state names; should contain "default"
-- pinctrl-0: the default pinctrl state (active)
-- pinctrl-n: the "sleep" pinctrl state
-- port: DSI controller output port. This contains one endpoint subnode, with its
-  remote-endpoint set to the phandle of the connected panel's endpoint.
-  See Documentation/devicetree/bindings/graph.txt for device graph info.
-
-DSI PHY:
-Required properties:
-- compatible: Could be the following
-  * "qcom,dsi-phy-28nm-hpm"
-  * "qcom,dsi-phy-28nm-lp"
-  * "qcom,dsi-phy-20nm"
-- reg: Physical base address and length of the registers of PLL, PHY and PHY
-  regulator
-- reg-names: The names of register regions. The following regions are required:
-  * "dsi_pll"
-  * "dsi_phy"
-  * "dsi_phy_regulator"
-- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should
-  be 0 or 1, since we have 2 DSI PHYs at most for now.
-- power-domains: Should be <&mmcc MDSS_GDSC>.
-- clocks: device clocks
-  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
-  * "iface_clk"
-- vddio-supply: phandle to vdd-io regulator device node
-
-Optional properties:
-- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
-  regulator is wanted.
-
-Example:
-       mdss_dsi0: qcom,mdss_dsi@fd922800 {
-               compatible = "qcom,mdss-dsi-ctrl";
-               qcom,dsi-host-index = <0>;
-               interrupt-parent = <&mdss_mdp>;
-               interrupts = <4 0>;
-               reg-names = "dsi_ctrl";
-               reg = <0xfd922800 0x200>;
-               power-domains = <&mmcc MDSS_GDSC>;
-               clock-names =
-                       "bus_clk",
-                       "byte_clk",
-                       "core_clk",
-                       "core_mmss_clk",
-                       "iface_clk",
-                       "mdp_core_clk",
-                       "pixel_clk";
-               clocks =
-                       <&mmcc MDSS_AXI_CLK>,
-                       <&mmcc MDSS_BYTE0_CLK>,
-                       <&mmcc MDSS_ESC0_CLK>,
-                       <&mmcc MMSS_MISC_AHB_CLK>,
-                       <&mmcc MDSS_AHB_CLK>,
-                       <&mmcc MDSS_MDP_CLK>,
-                       <&mmcc MDSS_PCLK0_CLK>;
-               vdda-supply = <&pma8084_l2>;
-               vdd-supply = <&pma8084_l22>;
-               vddio-supply = <&pma8084_l12>;
-
-               qcom,dsi-phy = <&mdss_dsi_phy0>;
-
-               qcom,dual-dsi-mode;
-               qcom,master-dsi;
-               qcom,sync-dual-dsi;
-
-               pinctrl-names = "default", "sleep";
-               pinctrl-0 = <&mdss_dsi_active>;
-               pinctrl-1 = <&mdss_dsi_suspend>;
-
-               panel: panel@0 {
-                       compatible = "sharp,lq101r1sx01";
-                       reg = <0>;
-                       link2 = <&secondary>;
-
-                       power-supply = <...>;
-                       backlight = <...>;
-
-                       port {
-                               panel_in: endpoint {
-                                       remote-endpoint = <&dsi0_out>;
-                               };
-                       };
-               };
-
-               port {
-                       dsi0_out: endpoint {
-                               remote-endpoint = <&panel_in>;
-                       };
-               };
-       };
-
-       mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 {
-               compatible = "qcom,dsi-phy-28nm-hpm";
-               qcom,dsi-phy-index = <0>;
-               reg-names =
-                       "dsi_pll",
-                       "dsi_phy",
-                       "dsi_phy_regulator";
-               reg =   <0xfd922a00 0xd4>,
-                       <0xfd922b00 0x2b0>,
-                       <0xfd922d80 0x7b>;
-               clock-names = "iface_clk";
-               clocks = <&mmcc MDSS_AHB_CLK>;
-               vddio-supply = <&pma8084_l12>;
-
-               qcom,dsi-phy-regulator-ldo-mode;
-       };
diff --git a/Documentation/devicetree/bindings/drm/msm/edp.txt b/Documentation/devicetree/bindings/drm/msm/edp.txt
deleted file mode 100644 (file)
index 3a20f6e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-Qualcomm Technologies Inc. adreno/snapdragon eDP output
-
-Required properties:
-- compatible:
-  * "qcom,mdss-edp"
-- reg: Physical base address and length of the registers of controller and PLL
-- reg-names: The names of register regions. The following regions are required:
-  * "edp"
-  * "pll_base"
-- interrupts: The interrupt signal from the eDP block.
-- power-domains: Should be <&mmcc MDSS_GDSC>.
-- clocks: device clocks
-  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
-  * "core_clk"
-  * "iface_clk"
-  * "mdp_core_clk"
-  * "pixel_clk"
-  * "link_clk"
-- #clock-cells: The value should be 1.
-- vdda-supply: phandle to vdda regulator device node
-- lvl-vdd-supply: phandle to regulator device node which is used to supply power
-  to HPD receiving chip
-- panel-en-gpios: GPIO pin to supply power to panel.
-- panel-hpd-gpios: GPIO pin used for eDP hpd.
-
-
-Optional properties:
-- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
-  through MDP block
-
-Example:
-       mdss_edp: qcom,mdss_edp@fd923400 {
-                       compatible = "qcom,mdss-edp";
-                       reg-names =
-                               "edp",
-                               "pll_base";
-                       reg =   <0xfd923400 0x700>,
-                               <0xfd923a00 0xd4>;
-                       interrupt-parent = <&mdss_mdp>;
-                       interrupts = <12 0>;
-                       power-domains = <&mmcc MDSS_GDSC>;
-                       clock-names =
-                               "core_clk",
-                               "pixel_clk",
-                               "iface_clk",
-                               "link_clk",
-                               "mdp_core_clk";
-                       clocks =
-                               <&mmcc MDSS_EDPAUX_CLK>,
-                               <&mmcc MDSS_EDPPIXEL_CLK>,
-                               <&mmcc MDSS_AHB_CLK>,
-                               <&mmcc MDSS_EDPLINK_CLK>,
-                               <&mmcc MDSS_MDP_CLK>;
-                       #clock-cells = <1>;
-                       vdda-supply = <&pma8084_l12>;
-                       lvl-vdd-supply = <&lvl_vreg>;
-                       panel-en-gpios = <&tlmm 137 0>;
-                       panel-hpd-gpios = <&tlmm 103 0>;
-       };
diff --git a/Documentation/devicetree/bindings/drm/msm/gpu.txt b/Documentation/devicetree/bindings/drm/msm/gpu.txt
deleted file mode 100644 (file)
index 67d0a58..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-Qualcomm adreno/snapdragon GPU
-
-Required properties:
-- compatible: "qcom,adreno-3xx"
-- reg: Physical base address and length of the controller's registers.
-- interrupts: The interrupt signal from the gpu.
-- clocks: device clocks
-  See ../clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
-  * "core_clk"
-  * "iface_clk"
-  * "mem_iface_clk"
-- qcom,chipid: gpu chip-id.  Note this may become optional for future
-  devices if we can reliably read the chipid from hw
-- qcom,gpu-pwrlevels: list of operating points
-  - compatible: "qcom,gpu-pwrlevels"
-  - for each qcom,gpu-pwrlevel:
-    - qcom,gpu-freq: requested gpu clock speed
-    - NOTE: downstream android driver defines additional parameters to
-      configure memory bandwidth scaling per OPP.
-
-Example:
-
-/ {
-       ...
-
-       gpu: qcom,kgsl-3d0@4300000 {
-               compatible = "qcom,adreno-3xx";
-               reg = <0x04300000 0x20000>;
-               reg-names = "kgsl_3d0_reg_memory";
-               interrupts = <GIC_SPI 80 0>;
-               interrupt-names = "kgsl_3d0_irq";
-               clock-names =
-                   "core_clk",
-                   "iface_clk",
-                   "mem_iface_clk";
-               clocks =
-                   <&mmcc GFX3D_CLK>,
-                   <&mmcc GFX3D_AHB_CLK>,
-                   <&mmcc MMSS_IMEM_AHB_CLK>;
-               qcom,chipid = <0x03020100>;
-               qcom,gpu-pwrlevels {
-                       compatible = "qcom,gpu-pwrlevels";
-                       qcom,gpu-pwrlevel@0 {
-                               qcom,gpu-freq = <450000000>;
-                       };
-                       qcom,gpu-pwrlevel@1 {
-                               qcom,gpu-freq = <27000000>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi.txt b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
deleted file mode 100644 (file)
index e926239..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Qualcomm adreno/snapdragon hdmi output
-
-Required properties:
-- compatible: one of the following
-   * "qcom,hdmi-tx-8994"
-   * "qcom,hdmi-tx-8084"
-   * "qcom,hdmi-tx-8974"
-   * "qcom,hdmi-tx-8660"
-   * "qcom,hdmi-tx-8960"
-- reg: Physical base address and length of the controller's registers
-- reg-names: "core_physical"
-- interrupts: The interrupt signal from the hdmi block.
-- clocks: device clocks
-  See ../clocks/clock-bindings.txt for details.
-- qcom,hdmi-tx-ddc-clk-gpio: ddc clk pin
-- qcom,hdmi-tx-ddc-data-gpio: ddc data pin
-- qcom,hdmi-tx-hpd-gpio: hpd pin
-- core-vdda-supply: phandle to supply regulator
-- hdmi-mux-supply: phandle to mux regulator
-
-Optional properties:
-- qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin
-- qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin
-- pinctrl-names: the pin control state names; should contain "default"
-- pinctrl-0: the default pinctrl state (active)
-- pinctrl-1: the "sleep" pinctrl state
-
-Example:
-
-/ {
-       ...
-
-       hdmi: qcom,hdmi-tx-8960@4a00000 {
-               compatible = "qcom,hdmi-tx-8960";
-               reg-names = "core_physical";
-               reg = <0x04a00000 0x1000>;
-               interrupts = <GIC_SPI 79 0>;
-               clock-names =
-                   "core_clk",
-                   "master_iface_clk",
-                   "slave_iface_clk";
-               clocks =
-                   <&mmcc HDMI_APP_CLK>,
-                   <&mmcc HDMI_M_AHB_CLK>,
-                   <&mmcc HDMI_S_AHB_CLK>;
-               qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>;
-               qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>;
-               qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
-               core-vdda-supply = <&pm8921_hdmi_mvs>;
-               hdmi-mux-supply = <&ext_3p3v>;
-               pinctrl-names = "default", "sleep";
-               pinctrl-0 = <&hpd_active  &ddc_active  &cec_active>;
-               pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt
deleted file mode 100644 (file)
index 1a0598e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Qualcomm adreno/snapdragon display controller
-
-Required properties:
-- compatible:
-  * "qcom,mdp" - mdp4
-- reg: Physical base address and length of the controller's registers.
-- interrupts: The interrupt signal from the display controller.
-- connectors: array of phandles for output device(s)
-- clocks: device clocks
-  See ../clocks/clock-bindings.txt for details.
-- clock-names: the following clocks are required:
-  * "core_clk"
-  * "iface_clk"
-  * "lut_clk"
-  * "src_clk"
-  * "hdmi_clk"
-  * "mpd_clk"
-
-Optional properties:
-- gpus: phandle for gpu device
-
-Example:
-
-/ {
-       ...
-
-       mdp: qcom,mdp@5100000 {
-               compatible = "qcom,mdp";
-               reg = <0x05100000 0xf0000>;
-               interrupts = <GIC_SPI 75 0>;
-               connectors = <&hdmi>;
-               gpus = <&gpu>;
-               clock-names =
-                   "core_clk",
-                   "iface_clk",
-                   "lut_clk",
-                   "src_clk",
-                   "hdmi_clk",
-                   "mdp_clk";
-               clocks =
-                   <&mmcc MDP_SRC>,
-                   <&mmcc MDP_AHB_CLK>,
-                   <&mmcc MDP_LUT_CLK>,
-                   <&mmcc TV_SRC>,
-                   <&mmcc HDMI_TV_CLK>,
-                   <&mmcc MDP_TV_CLK>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/panel.txt b/Documentation/devicetree/bindings/drm/tilcdc/panel.txt
deleted file mode 100644 (file)
index 4ab9e23..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Device-Tree bindings for tilcdc DRM generic panel output driver
-
-Required properties:
- - compatible: value should be "ti,tilcdc,panel".
- - panel-info: configuration info to configure LCDC correctly for the panel
-   - ac-bias: AC Bias Pin Frequency
-   - ac-bias-intrpt: AC Bias Pin Transitions per Interrupt
-   - dma-burst-sz: DMA burst size
-   - bpp: Bits per pixel
-   - fdd: FIFO DMA Request Delay
-   - sync-edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
-   - sync-ctrl: Horizontal and Vertical Sync: Control: 0=ignore
-   - raster-order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
-   - fifo-th: DMA FIFO threshold
- - display-timings: typical videomode of lcd panel.  Multiple video modes
-   can be listed if the panel supports multiple timings, but the 'native-mode'
-   should be the preferred/default resolution.  Refer to
-   Documentation/devicetree/bindings/video/display-timing.txt for display
-   timing binding details.
-
-Optional properties:
-- backlight: phandle of the backlight device attached to the panel
-- enable-gpios: GPIO pin to enable or disable the panel
-
-Recommended properties:
- - pinctrl-names, pinctrl-0: the pincontrol settings to configure
-   muxing properly for pins that connect to TFP410 device
-
-Example:
-
-       /* Settings for CDTech_S035Q01 / LCD3 cape: */
-       lcd3 {
-               compatible = "ti,tilcdc,panel";
-               pinctrl-names = "default";
-               pinctrl-0 = <&bone_lcd3_cape_lcd_pins>;
-               backlight = <&backlight>;
-               enable-gpios = <&gpio3 19 0>;
-
-               panel-info {
-                       ac-bias           = <255>;
-                       ac-bias-intrpt    = <0>;
-                       dma-burst-sz      = <16>;
-                       bpp               = <16>;
-                       fdd               = <0x80>;
-                       sync-edge         = <0>;
-                       sync-ctrl         = <1>;
-                       raster-order      = <0>;
-                       fifo-th           = <0>;
-               };
-               display-timings {
-                       native-mode = <&timing0>;
-                       timing0: 320x240 {
-                               hactive         = <320>;
-                               vactive         = <240>;
-                               hback-porch     = <21>;
-                               hfront-porch    = <58>;
-                               hsync-len       = <47>;
-                               vback-porch     = <11>;
-                               vfront-porch    = <23>;
-                               vsync-len       = <2>;
-                               clock-frequency = <8000000>;
-                               hsync-active    = <0>;
-                               vsync-active    = <0>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tfp410.txt b/Documentation/devicetree/bindings/drm/tilcdc/tfp410.txt
deleted file mode 100644 (file)
index a58ae77..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Device-Tree bindings for tilcdc DRM TFP410 output driver
-
-Required properties:
- - compatible: value should be "ti,tilcdc,tfp410".
- - i2c: the phandle for the i2c device to use for DDC
-
-Recommended properties:
- - pinctrl-names, pinctrl-0: the pincontrol settings to configure
-   muxing properly for pins that connect to TFP410 device
- - powerdn-gpio: the powerdown GPIO, pulled low to power down the
-   TFP410 device (for DPMS_OFF)
-
-Example:
-
-       dvicape {
-               compatible = "ti,tilcdc,tfp410";
-               i2c = <&i2c2>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>;
-               powerdn-gpio = <&gpio2 31 0>;
-       };
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
deleted file mode 100644 (file)
index 2136ee8..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-Device-Tree bindings for tilcdc DRM driver
-
-Required properties:
- - compatible: value should be "ti,am33xx-tilcdc".
- - interrupts: the interrupt number
- - reg: base address and size of the LCDC device
-
-Recommended properties:
- - interrupt-parent: the phandle for the interrupt controller that
-   services interrupts for this device.
- - ti,hwmods: Name of the hwmod associated to the LCDC
-
-Optional properties:
- - max-bandwidth: The maximum pixels per second that the memory
-   interface / lcd controller combination can sustain
- - max-width: The maximum horizontal pixel width supported by
-   the lcd controller.
- - max-pixelclock: The maximum pixel clock that can be supported
-   by the lcd controller in KHz.
-
-Optional nodes:
-
- - port/ports: to describe a connection to an external encoder. The
-   binding follows Documentation/devicetree/bindings/graph.txt and
-   suppors a single port with a single endpoint.
-
-Example:
-
-       fb: fb@4830e000 {
-               compatible = "ti,am33xx-tilcdc";
-               reg = <0x4830e000 0x1000>;
-               interrupt-parent = <&intc>;
-               interrupts = <36>;
-               ti,hwmods = "lcdc";
-
-               port {
-                       lcdc_0: endpoint@0 {
-                               remote-endpoint = <&hdmi_0>;
-                       };
-               };
-       };
-
-       tda19988: tda19988 {
-               compatible = "nxp,tda998x";
-               reg = <0x70>;
-
-               pinctrl-names = "default", "off";
-               pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
-               pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
-
-               port {
-                       hdmi_0: endpoint@0 {
-                               remote-endpoint = <&lcdc_0>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/eeprom.txt b/Documentation/devicetree/bindings/eeprom.txt
deleted file mode 100644 (file)
index 4342c10..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-EEPROMs (I2C)
-
-Required properties:
-
-  - compatible : should be "<manufacturer>,<type>"
-                If there is no specific driver for <manufacturer>, a generic
-                driver based on <type> is selected. Possible types are:
-                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
-                24c128, 24c256, 24c512, 24c1024, spd
-
-  - reg : the I2C address of the EEPROM
-
-Optional properties:
-
-  - pagesize : the length of the pagesize for writing. Please consult the
-               manual of your device, that value varies a lot. A wrong value
-              may result in data loss! If not specified, a safety value of
-              '1' is used which will be very slow.
-
-  - read-only: this parameterless property disables writes to the eeprom
-
-Example:
-
-eeprom@52 {
-       compatible = "atmel,24c32";
-       reg = <0x52>;
-       pagesize = <32>;
-};
diff --git a/Documentation/devicetree/bindings/eeprom/at25.txt b/Documentation/devicetree/bindings/eeprom/at25.txt
new file mode 100644 (file)
index 0000000..1d34471
--- /dev/null
@@ -0,0 +1,35 @@
+EEPROMs (SPI) compatible with Atmel at25.
+
+Required properties:
+- compatible : "atmel,at25".
+- reg : chip select number
+- spi-max-frequency : max spi frequency to use
+- pagesize : size of the eeprom page
+- size : total eeprom size in bytes
+- address-width : number of address bits (one of 8, 16, or 24)
+
+Optional properties:
+- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
+- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
+- read-only : this parameter-less property disables writes to the eeprom
+
+Obsolete legacy properties are can be used in place of "size", "pagesize",
+"address-width", and "read-only":
+- at25,byte-len : total eeprom size in bytes
+- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
+- at25,page-size : size of the eeprom page
+
+Additional compatible properties are also allowed.
+
+Example:
+       at25@0 {
+               compatible = "atmel,at25", "st,m95256";
+               reg = <0>
+               spi-max-frequency = <5000000>;
+               spi-cpha;
+               spi-cpol;
+
+               pagesize = <64>;
+               size = <32768>;
+               address-width = <16>;
+       };
diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
new file mode 100644 (file)
index 0000000..4342c10
--- /dev/null
@@ -0,0 +1,28 @@
+EEPROMs (I2C)
+
+Required properties:
+
+  - compatible : should be "<manufacturer>,<type>"
+                If there is no specific driver for <manufacturer>, a generic
+                driver based on <type> is selected. Possible types are:
+                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
+                24c128, 24c256, 24c512, 24c1024, spd
+
+  - reg : the I2C address of the EEPROM
+
+Optional properties:
+
+  - pagesize : the length of the pagesize for writing. Please consult the
+               manual of your device, that value varies a lot. A wrong value
+              may result in data loss! If not specified, a safety value of
+              '1' is used which will be very slow.
+
+  - read-only: this parameterless property disables writes to the eeprom
+
+Example:
+
+eeprom@52 {
+       compatible = "atmel,24c32";
+       reg = <0x52>;
+       pagesize = <32>;
+};
diff --git a/Documentation/devicetree/bindings/fb/mxsfb.txt b/Documentation/devicetree/bindings/fb/mxsfb.txt
deleted file mode 100644 (file)
index 96ec517..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-* Freescale MXS LCD Interface (LCDIF)
-
-Required properties:
-- compatible: Should be "fsl,<chip>-lcdif".  Supported chips include
-  imx23 and imx28.
-- reg: Address and length of the register set for lcdif
-- interrupts: Should contain lcdif interrupts
-- display : phandle to display node (see below for details)
-
-* display node
-
-Required properties:
-- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
-- bus-width : number of data lines.  Could be <8>, <16>, <18> or <24>.
-
-Required sub-node:
-- display-timings : Refer to binding doc display-timing.txt for details.
-
-Examples:
-
-lcdif@80030000 {
-       compatible = "fsl,imx28-lcdif";
-       reg = <0x80030000 2000>;
-       interrupts = <38 86>;
-
-       display: display {
-               bits-per-pixel = <32>;
-               bus-width = <24>;
-
-               display-timings {
-                       native-mode = <&timing0>;
-                       timing0: timing0 {
-                               clock-frequency = <33500000>;
-                               hactive = <800>;
-                               vactive = <480>;
-                               hfront-porch = <164>;
-                               hback-porch = <89>;
-                               hsync-len = <10>;
-                               vback-porch = <23>;
-                               vfront-porch = <10>;
-                               vsync-len = <10>;
-                               hsync-active = <0>;
-                               vsync-active = <0>;
-                               de-active = <1>;
-                               pixelclk-active = <0>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/fb/sm501fb.txt b/Documentation/devicetree/bindings/fb/sm501fb.txt
deleted file mode 100644 (file)
index 9d9f009..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-* SM SM501
-
-The SM SM501 is a LCD controller, with proper hardware, it can also
-drive DVI monitors.
-
-Required properties:
-- compatible : should be "smi,sm501".
-- reg : contain two entries:
-    - First entry: System Configuration register
-    - Second entry: IO space (Display Controller register)
-- interrupts : SMI interrupt to the cpu should be described here.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Optional properties:
-- mode : select a video mode:
-    <xres>x<yres>[-<bpp>][@<refresh>]
-- edid : verbatim EDID data block describing attached display.
-  Data from the detailed timing descriptor will be used to
-  program the display controller.
-- little-endian: available on big endian systems, to
-  set different foreign endian.
-- big-endian: available on little endian systems, to
-  set different foreign endian.
-
-Example for MPC5200:
-       display@1,0 {
-               compatible = "smi,sm501";
-               reg = <1 0x00000000 0x00800000
-                      1 0x03e00000 0x00200000>;
-               interrupts = <1 1 3>;
-               mode = "640x480-32@60";
-               edid = [edid-data];
-       };
index 9b027a615486a9d1560bb72cbc4662a512e33815..d52f3340414d056ea2e813249ec0eb908eca8c8d 100644 (file)
@@ -9,7 +9,7 @@ Required properties:
 
 Example:
 
-       hps_0_fpgamgr: fpgamgr@0xff706000 {
+       hps_0_fpgamgr: fpgamgr@ff706000 {
                compatible = "altr,socfpga-fpga-mgr";
                reg = <0xFF706000 0x1000
                       0xFFB90000 0x1000>;
diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
deleted file mode 100644 (file)
index e685610..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-NVIDIA Tegra host1x
-
-Required properties:
-- compatible: "nvidia,tegra<chip>-host1x"
-- reg: Physical base address and length of the controller's registers.
-- interrupts: The interrupt outputs from the controller.
-- #address-cells: The number of cells used to represent physical base addresses
-  in the host1x address space. Should be 1.
-- #size-cells: The number of cells used to represent the size of an address
-  range in the host1x address space. Should be 1.
-- ranges: The mapping of the host1x address space to the CPU address space.
-- clocks: Must contain one entry, for the module clock.
-  See ../clocks/clock-bindings.txt for details.
-- resets: Must contain an entry for each entry in reset-names.
-  See ../reset/reset.txt for details.
-- reset-names: Must include the following entries:
-  - host1x
-
-The host1x top-level node defines a number of children, each representing one
-of the following host1x client modules:
-
-- mpe: video encoder
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-mpe"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - mpe
-
-- vi: video input
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-vi"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - vi
-
-- epp: encoder pre-processor
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-epp"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - epp
-
-- isp: image signal processor
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-isp"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - isp
-
-- gr2d: 2D graphics engine
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-gr2d"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - 2d
-
-- gr3d: 3D graphics engine
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-gr3d"
-  - reg: Physical base address and length of the controller's registers.
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    (This property may be omitted if the only clock in the list is "3d")
-    - 3d
-      This MUST be the first entry.
-    - 3d2 (Only required on SoCs with two 3D clocks)
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - 3d
-    - 3d2 (Only required on SoCs with two 3D clocks)
-
-- dc: display controller
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-dc"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    - dc
-      This MUST be the first entry.
-    - parent
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - dc
-  - nvidia,head: The number of the display controller head. This is used to
-    setup the various types of output to receive video data from the given
-    head.
-
-  Each display controller node has a child node, named "rgb", that represents
-  the RGB output associated with the controller. It can take the following
-  optional properties:
-  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
-  - nvidia,edid: supplies a binary EDID blob
-  - nvidia,panel: phandle of a display panel
-
-- hdmi: High Definition Multimedia Interface
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-hdmi"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - hdmi-supply: supply for the +5V HDMI connector pin
-  - vdd-supply: regulator for supply voltage
-  - pll-supply: regulator for PLL
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    - hdmi
-      This MUST be the first entry.
-    - parent
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - hdmi
-
-  Optional properties:
-  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
-  - nvidia,edid: supplies a binary EDID blob
-  - nvidia,panel: phandle of a display panel
-
-- tvo: TV encoder output
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-tvo"
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain one entry, for the module clock.
-    See ../clocks/clock-bindings.txt for details.
-
-- dsi: display serial interface
-
-  Required properties:
-  - compatible: "nvidia,tegra<chip>-dsi"
-  - reg: Physical base address and length of the controller's registers.
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    - dsi
-      This MUST be the first entry.
-    - lp
-    - parent
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - dsi
-  - avdd-dsi-supply: phandle of a supply that powers the DSI controller
-  - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying
-    which pads are used by this DSI output and need to be calibrated. See also
-    ../mipi/nvidia,tegra114-mipi.txt.
-
-  Optional properties:
-  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
-  - nvidia,edid: supplies a binary EDID blob
-  - nvidia,panel: phandle of a display panel
-  - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang
-    up with in order to support up to 8 data lanes
-
-- sor: serial output resource
-
-  Required properties:
-  - compatible: Should be:
-    - "nvidia,tegra124-sor": for Tegra124 and Tegra132
-    - "nvidia,tegra132-sor": for Tegra132
-    - "nvidia,tegra210-sor": for Tegra210
-    - "nvidia,tegra210-sor1": for Tegra210
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    - sor: clock input for the SOR hardware
-    - parent: input for the pixel clock
-    - dp: reference clock for the SOR clock
-    - safe: safe reference for the SOR clock during power up
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - sor
-
-  Optional properties:
-  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
-  - nvidia,edid: supplies a binary EDID blob
-  - nvidia,panel: phandle of a display panel
-
-  Optional properties when driving an eDP output:
-  - nvidia,dpaux: phandle to a DispayPort AUX interface
-
-- dpaux: DisplayPort AUX interface
-  - compatible: For Tegra124, must contain "nvidia,tegra124-dpaux".  Otherwise,
-    must contain '"nvidia,<chip>-dpaux", "nvidia,tegra124-dpaux"', where
-    <chip> is tegra132.
-  - reg: Physical base address and length of the controller's registers.
-  - interrupts: The interrupt outputs from the controller.
-  - clocks: Must contain an entry for each entry in clock-names.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: Must include the following entries:
-    - dpaux: clock input for the DPAUX hardware
-    - parent: reference clock
-  - resets: Must contain an entry for each entry in reset-names.
-    See ../reset/reset.txt for details.
-  - reset-names: Must include the following entries:
-    - dpaux
-  - vdd-supply: phandle of a supply that powers the DisplayPort link
-
-Example:
-
-/ {
-       ...
-
-       host1x {
-               compatible = "nvidia,tegra20-host1x", "simple-bus";
-               reg = <0x50000000 0x00024000>;
-               interrupts = <0 65 0x04   /* mpcore syncpt */
-                             0 67 0x04>; /* mpcore general */
-               clocks = <&tegra_car TEGRA20_CLK_HOST1X>;
-               resets = <&tegra_car 28>;
-               reset-names = "host1x";
-
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               ranges = <0x54000000 0x54000000 0x04000000>;
-
-               mpe {
-                       compatible = "nvidia,tegra20-mpe";
-                       reg = <0x54040000 0x00040000>;
-                       interrupts = <0 68 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_MPE>;
-                       resets = <&tegra_car 60>;
-                       reset-names = "mpe";
-               };
-
-               vi {
-                       compatible = "nvidia,tegra20-vi";
-                       reg = <0x54080000 0x00040000>;
-                       interrupts = <0 69 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_VI>;
-                       resets = <&tegra_car 100>;
-                       reset-names = "vi";
-               };
-
-               epp {
-                       compatible = "nvidia,tegra20-epp";
-                       reg = <0x540c0000 0x00040000>;
-                       interrupts = <0 70 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_EPP>;
-                       resets = <&tegra_car 19>;
-                       reset-names = "epp";
-               };
-
-               isp {
-                       compatible = "nvidia,tegra20-isp";
-                       reg = <0x54100000 0x00040000>;
-                       interrupts = <0 71 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_ISP>;
-                       resets = <&tegra_car 23>;
-                       reset-names = "isp";
-               };
-
-               gr2d {
-                       compatible = "nvidia,tegra20-gr2d";
-                       reg = <0x54140000 0x00040000>;
-                       interrupts = <0 72 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_GR2D>;
-                       resets = <&tegra_car 21>;
-                       reset-names = "2d";
-               };
-
-               gr3d {
-                       compatible = "nvidia,tegra20-gr3d";
-                       reg = <0x54180000 0x00040000>;
-                       clocks = <&tegra_car TEGRA20_CLK_GR3D>;
-                       resets = <&tegra_car 24>;
-                       reset-names = "3d";
-               };
-
-               dc@54200000 {
-                       compatible = "nvidia,tegra20-dc";
-                       reg = <0x54200000 0x00040000>;
-                       interrupts = <0 73 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_DISP1>,
-                                <&tegra_car TEGRA20_CLK_PLL_P>;
-                       clock-names = "dc", "parent";
-                       resets = <&tegra_car 27>;
-                       reset-names = "dc";
-
-                       rgb {
-                               status = "disabled";
-                       };
-               };
-
-               dc@54240000 {
-                       compatible = "nvidia,tegra20-dc";
-                       reg = <0x54240000 0x00040000>;
-                       interrupts = <0 74 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_DISP2>,
-                                <&tegra_car TEGRA20_CLK_PLL_P>;
-                       clock-names = "dc", "parent";
-                       resets = <&tegra_car 26>;
-                       reset-names = "dc";
-
-                       rgb {
-                               status = "disabled";
-                       };
-               };
-
-               hdmi {
-                       compatible = "nvidia,tegra20-hdmi";
-                       reg = <0x54280000 0x00040000>;
-                       interrupts = <0 75 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_HDMI>,
-                                <&tegra_car TEGRA20_CLK_PLL_D_OUT0>;
-                       clock-names = "hdmi", "parent";
-                       resets = <&tegra_car 51>;
-                       reset-names = "hdmi";
-                       status = "disabled";
-               };
-
-               tvo {
-                       compatible = "nvidia,tegra20-tvo";
-                       reg = <0x542c0000 0x00040000>;
-                       interrupts = <0 76 0x04>;
-                       clocks = <&tegra_car TEGRA20_CLK_TVO>;
-                       status = "disabled";
-               };
-
-               dsi {
-                       compatible = "nvidia,tegra20-dsi";
-                       reg = <0x54300000 0x00040000>;
-                       clocks = <&tegra_car TEGRA20_CLK_DSI>,
-                                <&tegra_car TEGRA20_CLK_PLL_D_OUT0>;
-                       clock-names = "dsi", "parent";
-                       resets = <&tegra_car 48>;
-                       reset-names = "dsi";
-                       status = "disabled";
-               };
-       };
-
-       ...
-};
diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
deleted file mode 100644 (file)
index a36dfce..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-STMicroelectronics stih4xx platforms
-
-- sti-vtg: video timing generator
-  Required properties:
-  - compatible: "st,vtg"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  Optional properties:
-  - interrupts : VTG interrupt number to the CPU.
-  - st,slave: phandle on a slave vtg
-
-- sti-vtac: video timing advanced inter dye communication Rx and TX
-  Required properties:
-  - compatible: "st,vtac-main" or "st,vtac-aux"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-
-- sti-display-subsystem: Master device for DRM sub-components
-  This device must be the parent of all the sub-components and is responsible
-  of bind them.
-  Required properties:
-  - compatible: "st,sti-display-subsystem"
-  - ranges: to allow probing of subdevices
-
-- sti-compositor: frame compositor engine
-  must be a child of sti-display-subsystem
-  Required properties:
-  - compatible: "st,stih<chip>-compositor"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-  - resets: resets to be used by the device
-    See ../reset/reset.txt for details.
-  - reset-names: names of the resets listed in resets property in the same
-    order.
-  - st,vtg: phandle(s) on vtg device (main and aux) nodes.
-
-- sti-tvout: video out hardware block
-  must be a child of sti-display-subsystem
-  Required properties:
-  - compatible: "st,stih<chip>-tvout"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - reg-names: names of the mapped memory regions listed in regs property in
-    the same order.
-  - resets: resets to be used by the device
-    See ../reset/reset.txt for details.
-  - reset-names: names of the resets listed in resets property in the same
-    order.
-
-- sti-hdmi: hdmi output block
-  must be a child of sti-display-subsystem
-  Required properties:
-  - compatible: "st,stih<chip>-hdmi";
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - reg-names: names of the mapped memory regions listed in regs property in
-    the same order.
-  - interrupts : HDMI interrupt number to the CPU.
-  - interrupt-names: name of the interrupts listed in interrupts property in
-    the same order
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-  - ddc: phandle of an I2C controller used for DDC EDID probing
-
-sti-hda:
-  Required properties:
-  must be a child of sti-display-subsystem
-  - compatible: "st,stih<chip>-hda"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - reg-names: names of the mapped memory regions listed in regs property in
-    the same order.
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-
-sti-dvo:
-  Required properties:
-  must be a child of sti-display-subsystem
-  - compatible: "st,stih<chip>-dvo"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - reg-names: names of the mapped memory regions listed in regs property in
-    the same order.
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-  - pinctrl-0: pin control handle
-  - pinctrl-name: names of the pin control to use
-  - sti,panel: phandle of the panel connected to the DVO output
-
-sti-hqvdp:
-  must be a child of sti-display-subsystem
-  Required properties:
-  - compatible: "st,stih<chip>-hqvdp"
-  - reg: Physical base address of the IP registers and length of memory mapped region.
-  - clocks: from common clock binding: handle hardware IP needed clocks, the
-    number of clocks may depend of the SoC type.
-    See ../clocks/clock-bindings.txt for details.
-  - clock-names: names of the clocks listed in clocks property in the same
-    order.
-  - resets: resets to be used by the device
-    See ../reset/reset.txt for details.
-  - reset-names: names of the resets listed in resets property in the same
-    order.
-  - st,vtg: phandle on vtg main device node.
-
-Example:
-
-/ {
-       ...
-
-       vtg_main_slave: sti-vtg-main-slave@fe85A800 {
-               compatible      = "st,vtg";
-               reg             = <0xfe85A800 0x300>;
-               interrupts      = <GIC_SPI 175 IRQ_TYPE_NONE>;
-       };
-
-       vtg_main: sti-vtg-main-master@fd348000 {
-               compatible      = "st,vtg";
-               reg             = <0xfd348000 0x400>;
-               st,slave        = <&vtg_main_slave>;
-       };
-
-       vtg_aux_slave: sti-vtg-aux-slave@fd348400 {
-               compatible      = "st,vtg";
-               reg             = <0xfe858200 0x300>;
-               interrupts      = <GIC_SPI 176 IRQ_TYPE_NONE>;
-       };
-
-       vtg_aux: sti-vtg-aux-master@fd348400 {
-               compatible      = "st,vtg";
-               reg             = <0xfd348400 0x400>;
-               st,slave        = <&vtg_aux_slave>;
-       };
-
-
-       sti-vtac-rx-main@fee82800 {
-               compatible      = "st,vtac-main";
-               reg             = <0xfee82800 0x200>;
-               clock-names     = "vtac";
-               clocks          = <&clk_m_a2_div0 CLK_M_VTAC_MAIN_PHY>;
-       };
-
-       sti-vtac-rx-aux@fee82a00 {
-               compatible      = "st,vtac-aux";
-               reg             = <0xfee82a00 0x200>;
-               clock-names     = "vtac";
-               clocks          = <&clk_m_a2_div0 CLK_M_VTAC_AUX_PHY>;
-       };
-
-       sti-vtac-tx-main@fd349000 {
-               compatible      = "st,vtac-main";
-               reg             = <0xfd349000 0x200>, <0xfd320000 0x10000>;
-               clock-names     = "vtac";
-               clocks           = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
-       };
-
-       sti-vtac-tx-aux@fd349200 {
-               compatible      = "st,vtac-aux";
-               reg             = <0xfd349200 0x200>, <0xfd320000 0x10000>;
-               clock-names     = "vtac";
-               clocks          = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
-       };
-
-       sti-display-subsystem {
-               compatible = "st,sti-display-subsystem";
-               ranges;
-
-               sti-compositor@fd340000 {
-                       compatible      = "st,stih416-compositor";
-                       reg             = <0xfd340000 0x1000>;
-                       clock-names     = "compo_main", "compo_aux",
-                                         "pix_main", "pix_aux";
-                       clocks          = <&clk_m_a2_div1 CLK_M_COMPO_MAIN>, <&clk_m_a2_div1 CLK_M_COMPO_AUX>,
-                                         <&clockgen_c_vcc CLK_S_PIX_MAIN>, <&clockgen_c_vcc CLK_S_PIX_AUX>;
-                       reset-names     = "compo-main", "compo-aux";
-                       resets          = <&softreset STIH416_COMPO_M_SOFTRESET>, <&softreset STIH416_COMPO_A_SOFTRESET>;
-                       st,vtg          = <&vtg_main>, <&vtg_aux>;
-               };
-
-               sti-tvout@fe000000 {
-                       compatible      = "st,stih416-tvout";
-                       reg             = <0xfe000000 0x1000>, <0xfe85a000 0x400>, <0xfe830000 0x10000>;
-                       reg-names       = "tvout-reg", "hda-reg", "syscfg";
-                       reset-names     = "tvout";
-                       resets          = <&softreset STIH416_HDTVOUT_SOFTRESET>;
-               };
-
-               sti-hdmi@fe85c000 {
-                       compatible      = "st,stih416-hdmi";
-                       reg             = <0xfe85c000 0x1000>, <0xfe830000 0x10000>;
-                       reg-names       = "hdmi-reg", "syscfg";
-                       interrupts      = <GIC_SPI 173 IRQ_TYPE_NONE>;
-                       interrupt-names = "irq";
-                       clock-names     = "pix", "tmds", "phy", "audio";
-                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>;
-               };
-
-               sti-hda@fe85a000 {
-                       compatible      = "st,stih416-hda";
-                       reg             = <0xfe85a000 0x400>, <0xfe83085c 0x4>;
-                       reg-names       = "hda-reg", "video-dacs-ctrl";
-                       clock-names     = "pix", "hddac";
-                       clocks          = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
-               };
-
-               sti-dvo@8d00400 {
-                       compatible      = "st,stih407-dvo";
-                       reg             = <0x8d00400 0x200>;
-                       reg-names       = "dvo-reg";
-                       clock-names     = "dvo_pix", "dvo",
-                                         "main_parent", "aux_parent";
-                       clocks          = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
-                                         <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
-                       pinctrl-names   = "default";
-                       pinctrl-0       = <&pinctrl_dvo>;
-                       sti,panel       = <&panel_dvo>;
-               };
-
-               sti-hqvdp@9c000000 {
-                               compatible      = "st,stih407-hqvdp";
-                               reg             = <0x9C00000 0x100000>;
-                               clock-names     = "hqvdp", "pix_main";
-                               clocks          = <&clk_s_c0_flexgen CLK_MAIN_DISP>, <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>;
-                               reset-names     = "hqvdp";
-                               resets          = <&softreset STIH407_HDQVDP_SOFTRESET>;
-                               st,vtg          = <&vtg_main>;
-               };
-       };
-       ...
-};
diff --git a/Documentation/devicetree/bindings/hid/hid-over-i2c.txt b/Documentation/devicetree/bindings/hid/hid-over-i2c.txt
deleted file mode 100644 (file)
index 488edcb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-* HID over I2C Device-Tree bindings
-
-HID over I2C provides support for various Human Interface Devices over the
-I2C bus. These devices can be for example touchpads, keyboards, touch screens
-or sensors.
-
-The specification has been written by Microsoft and is currently available here:
-http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
-
-If this binding is used, the kernel module i2c-hid will handle the communication
-with the device and the generic hid core layer will handle the protocol.
-
-Required properties:
-- compatible: must be "hid-over-i2c"
-- reg: i2c slave address
-- hid-descr-addr: HID descriptor address
-- interrupt-parent: the phandle for the interrupt controller
-- interrupts: interrupt line
-
-Example:
-
-       i2c-hid-dev@2c {
-               compatible = "hid-over-i2c";
-               reg = <0x2c>;
-               hid-descr-addr = <0x0020>;
-               interrupt-parent = <&gpx3>;
-               interrupts = <3 2>;
-       };
diff --git a/Documentation/devicetree/bindings/hwmon/ina209.txt b/Documentation/devicetree/bindings/hwmon/ina209.txt
deleted file mode 100644 (file)
index 9dd2bee..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-ina209 properties
-
-Required properties:
-- compatible: Must be "ti,ina209"
-- reg: I2C address
-
-Optional properties:
-
-- shunt-resistor
-       Shunt resistor value in micro-Ohm
-
-Example:
-
-temp-sensor@4c {
-       compatible = "ti,ina209";
-       reg = <0x4c>;
-       shunt-resistor = <5000>;
-};
index a2ad85d7e74786230dff2c94c03d4417e54abf7a..9bcd5e87830d23882fa930c3b5214a94252f7957 100644 (file)
@@ -2,6 +2,7 @@ ina2xx properties
 
 Required properties:
 - compatible: Must be one of the following:
+       - "ti,ina209" for ina209
        - "ti,ina219" for ina219
        - "ti,ina220" for ina220
        - "ti,ina226" for ina226
diff --git a/Documentation/devicetree/bindings/hwrng/atmel-trng.txt b/Documentation/devicetree/bindings/hwrng/atmel-trng.txt
deleted file mode 100644 (file)
index 4ac5aaa..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Atmel TRNG (True Random Number Generator) block
-
-Required properties:
-- compatible : Should be "atmel,at91sam9g45-trng"
-- reg : Offset and length of the register set of this block
-- interrupts : the interrupt number for the TRNG block
-- clocks: should contain the TRNG clk source
-
-Example:
-
-trng@fffcc000 {
-       compatible = "atmel,at91sam9g45-trng";
-       reg = <0xfffcc000 0x4000>;
-       interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>;
-       clocks = <&trng_clk>;
-};
diff --git a/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt b/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt
deleted file mode 100644 (file)
index e25a456..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-HWRNG support for the iproc-rng200 driver
-
-Required properties:
-- compatible : "brcm,iproc-rng200"
-- reg : base address and size of control register block
-
-Example:
-
-rng {
-        compatible = "brcm,iproc-rng200";
-        reg = <0x18032000 0x28>;
-};
diff --git a/Documentation/devicetree/bindings/hwrng/omap_rng.txt b/Documentation/devicetree/bindings/hwrng/omap_rng.txt
deleted file mode 100644 (file)
index 6a62acd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-OMAP SoC HWRNG Module
-
-Required properties:
-
-- compatible : Should contain entries for this and backward compatible
-  RNG versions:
-  - "ti,omap2-rng" for OMAP2.
-  - "ti,omap4-rng" for OMAP4, OMAP5 and AM33XX.
-  Note that these two versions are incompatible.
-- ti,hwmods: Name of the hwmod associated with the RNG module
-- reg : Offset and length of the register set for the module
-- interrupts : the interrupt number for the RNG module.
-               Only used for "ti,omap4-rng".
-
-Example:
-/* AM335x */
-rng: rng@48310000 {
-       compatible = "ti,omap4-rng";
-       ti,hwmods = "rng";
-       reg = <0x48310000 0x2000>;
-       interrupts = <111>;
-};
diff --git a/Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt b/Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt
deleted file mode 100644 (file)
index 6616d15..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-HWRNG support for the timeriomem_rng driver
-
-Required properties:
-- compatible : "timeriomem_rng"
-- reg : base address to sample from
-- period : wait time in microseconds to use between samples
-
-N.B. currently 'reg' must be four bytes wide and aligned
-
-Example:
-
-hwrng@44 {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       compatible = "timeriomem_rng";
-       reg = <0x44 0x04>;
-       period = <1000000>;
-};
diff --git a/Documentation/devicetree/bindings/iio/accel/lis302.txt b/Documentation/devicetree/bindings/iio/accel/lis302.txt
new file mode 100644 (file)
index 0000000..2a19bff
--- /dev/null
@@ -0,0 +1,119 @@
+LIS302 accelerometer devicetree bindings
+
+This device is matched via its bus drivers, and has a number of properties
+that apply in on the generic device (independent from the bus).
+
+
+Required properties for the SPI bindings:
+ - compatible:                 should be set to "st,lis3lv02d_spi"
+ - reg:                        the chipselect index
+ - spi-max-frequency:  maximal bus speed, should be set to 1000000 unless
+                       constrained by external circuitry
+ - interrupts:         the interrupt generated by the device
+
+Required properties for the I2C bindings:
+ - compatible:         should be set to "st,lis3lv02d"
+ - reg:                        i2c slave address
+ - Vdd-supply:         The input supply for Vdd
+ - Vdd_IO-supply:      The input supply for Vdd_IO
+
+
+Optional properties for all bus drivers:
+
+ - st,click-single-{x,y,z}:    if present, tells the device to issue an
+                               interrupt on single click events on the
+                               x/y/z axis.
+ - st,click-double-{x,y,z}:    if present, tells the device to issue an
+                               interrupt on double click events on the
+                               x/y/z axis.
+ - st,click-thresh-{x,y,z}:    set the x/y/z axis threshold
+ - st,click-click-time-limit:  click time limit, from 0 to 127.5msec
+                               with step of 0.5 msec
+ - st,click-latency:           click latency, from 0 to 255 msec with
+                               step of 1 msec.
+ - st,click-window:            click window, from 0 to 255 msec with
+                               step of 1 msec.
+ - st,irq{1,2}-disable:                disable IRQ 1/2
+ - st,irq{1,2}-ff-wu-1:                raise IRQ 1/2 on FF_WU_1 condition
+ - st,irq{1,2}-ff-wu-2:                raise IRQ 1/2 on FF_WU_2 condition
+ - st,irq{1,2}-data-ready:     raise IRQ 1/2 on data ready contition
+ - st,irq{1,2}-click:          raise IRQ 1/2 on click condition
+ - st,irq-open-drain:          consider IRQ lines open-drain
+ - st,irq-active-low:          make IRQ lines active low
+ - st,wu-duration-1:           duration register for Free-Fall/Wake-Up
+                               interrupt 1
+ - st,wu-duration-2:           duration register for Free-Fall/Wake-Up
+                               interrupt 2
+ - st,wakeup-{x,y,z}-{lo,hi}:  set wakeup condition on x/y/z axis for
+                               upper/lower limit
+ - st,wakeup-threshold:                set wakeup threshold
+ - st,wakeup2-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for
+                               upper/lower limit for second wakeup
+                               engine.
+ - st,wakeup2-threshold:       set wakeup threshold for second wakeup
+                               engine.
+ - st,highpass-cutoff-hz=:     1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
+                               highpass cut-off frequency
+ - st,hipass{1,2}-disable:     disable highpass 1/2.
+ - st,default-rate=:           set the default rate
+ - st,axis-{x,y,z}=:           set the axis to map to the three coordinates.
+                               Negative values can be used for inverted axis.
+ - st,{min,max}-limit-{x,y,z}  set the min/max limits for x/y/z axis
+                               (used by self-test)
+
+
+Example for a SPI device node:
+
+       lis302@0 {
+               compatible = "st,lis302dl-spi";
+               reg = <0>;
+               spi-max-frequency = <1000000>;
+               interrupt-parent = <&gpio>;
+               interrupts = <104 0>;
+
+               st,click-single-x;
+               st,click-single-y;
+               st,click-single-z;
+               st,click-thresh-x = <10>;
+               st,click-thresh-y = <10>;
+               st,click-thresh-z = <10>;
+               st,irq1-click;
+               st,irq2-click;
+               st,wakeup-x-lo;
+               st,wakeup-x-hi;
+               st,wakeup-y-lo;
+               st,wakeup-y-hi;
+               st,wakeup-z-lo;
+               st,wakeup-z-hi;
+       };
+
+Example for a I2C device node:
+
+       lis331dlh: lis331dlh@18 {
+               compatible = "st,lis331dlh", "st,lis3lv02d";
+               reg = <0x18>;
+               Vdd-supply = <&lis3_reg>;
+               Vdd_IO-supply = <&lis3_reg>;
+
+               st,click-single-x;
+               st,click-single-y;
+               st,click-single-z;
+               st,click-thresh-x = <10>;
+               st,click-thresh-y = <10>;
+               st,click-thresh-z = <10>;
+               st,irq1-click;
+               st,irq2-click;
+               st,wakeup-x-lo;
+               st,wakeup-x-hi;
+               st,wakeup-y-lo;
+               st,wakeup-y-hi;
+               st,wakeup-z-lo;
+               st,wakeup-z-hi;
+               st,min-limit-x = <120>;
+               st,min-limit-y = <120>;
+               st,min-limit-z = <140>;
+               st,max-limit-x = <550>;
+               st,max-limit-y = <550>;
+               st,max-limit-z = <750>;
+       };
+
diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac7512.txt b/Documentation/devicetree/bindings/iio/dac/ti,dac7512.txt
new file mode 100644 (file)
index 0000000..1db4593
--- /dev/null
@@ -0,0 +1,20 @@
+TI DAC7512 DEVICETREE BINDINGS
+
+Required properties:
+
+       - "compatible"          Must be set to "ti,dac7512"
+
+Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
+apply. In particular, "reg" and "spi-max-frequency" properties must be given.
+
+
+Example:
+
+       spi_master {
+               dac7512: dac7512@0 {
+                       compatible = "ti,dac7512";
+                       reg = <0>; /* CS0 */
+                       spi-max-frequency = <1000000>;
+               };
+       };
+
diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.txt b/Documentation/devicetree/bindings/iio/pressure/bmp085.txt
new file mode 100644 (file)
index 0000000..d7a6deb
--- /dev/null
@@ -0,0 +1,24 @@
+BMP085/BMP18x digital pressure sensors
+
+Required properties:
+- compatible: bosch,bmp085
+
+Optional properties:
+- chip-id: configurable chip id for non-default chip revisions
+- temp-measurement-period: temperature measurement period (milliseconds)
+- default-oversampling: default oversampling value to be used at startup,
+  value range is 0-3 with rising sensitivity.
+- interrupt-parent: should be the phandle for the interrupt controller
+- interrupts: interrupt mapping for IRQ
+
+Example:
+
+pressure@77 {
+       compatible = "bosch,bmp085";
+       reg = <0x77>;
+       chip-id = <10>;
+       temp-measurement-period = <100>;
+       default-oversampling = <2>;
+       interrupt-parent = <&gpio0>;
+       interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+};
index df8b1279491d1ffd34e41cc41088f918511400de..33a1638b61d6bb950b45f0b14ceccaf7ff58eb19 100644 (file)
@@ -65,6 +65,7 @@ Optional properties:
        pendown-gpio                    GPIO handle describing the pin the !PENIRQ
                                        line is connected to.
        wakeup-source                   use any event on touchscreen as wakeup event.
+                                       (Legacy property support: "linux,wakeup")
 
 
 Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC::
@@ -86,6 +87,6 @@ Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC::
                        ti,x-plate-ohms = /bits/ 16 <40>;
                        ti,pressure-max = /bits/ 16 <255>;
 
-                       linux,wakeup;
+                       wakeup-source;
                };
        };
diff --git a/Documentation/devicetree/bindings/input/da9062-onkey.txt b/Documentation/devicetree/bindings/input/da9062-onkey.txt
new file mode 100644 (file)
index 0000000..ab0e048
--- /dev/null
@@ -0,0 +1,32 @@
+* Dialog DA9062/63 OnKey Module
+
+This module is part of the DA9062/DA9063. For more details about entire
+chips see Documentation/devicetree/bindings/mfd/da9062.txt and
+Documentation/devicetree/bindings/mfd/da9063.txt
+
+This module provides KEY_POWER, KEY_SLEEP and events.
+
+Required properties:
+
+- compatible: should be one of:
+       dlg,da9062-onkey
+       dlg,da9063-onkey
+
+Optional properties:
+
+  - dlg,disable-key-power : Disable power-down using a long key-press. If this
+    entry exists the OnKey driver will remove support for the KEY_POWER key
+    press. If this entry does not exist then by default the key-press
+    triggered power down is enabled and the OnKey will support both KEY_POWER
+    and KEY_SLEEP.
+
+Example:
+
+       pmic0: da9062@58 {
+
+               onkey {
+                       compatible = "dlg,da9063-onkey";
+                       dlg,disable-key-power;
+               };
+
+       };
index 5b91f5a3bd5c6aee02353423c3cdb8f56bd7bd22..95d0fb11a78753cdd272015e876bff704db1d726 100644 (file)
@@ -13,14 +13,22 @@ Subnode properties:
 
        - gpios: OF device-tree gpio specification.
        - label: Descriptive name of the key.
-       - linux,code: Keycode to emit.
+       - linux,code: Key / Axis code to emit.
 
 Optional subnode-properties:
        - linux,input-type: Specify event type this button/key generates.
          If not specified defaults to <1> == EV_KEY.
+       - linux,input-value: If linux,input-type is EV_ABS or EV_REL then this
+         value is sent for events this button generates when pressed.
+         EV_ABS/EV_REL axis will generate an event with a value of 0 when
+         all buttons with linux,input-type == type and linux,code == axis
+         are released. This value is interpreted as a signed 32 bit value,
+         e.g. to make a button generate a value of -1 use:
+         linux,input-value = <0xffffffff>; /* -1 */
        - debounce-interval: Debouncing interval time in milliseconds.
          If not specified defaults to 5.
        - wakeup-source: Boolean, button can wake-up the system.
+                        (Legacy property supported: "gpio-key,wakeup")
 
 Example nodes:
 
index 072bf7573c376ab3da5ab13d122d4f54d1a4f453..cf1333d1dd52974e4e960a7c97418f86864e56f1 100644 (file)
@@ -24,6 +24,7 @@ Optional subnode-properties:
        - debounce-interval: Debouncing interval time in milliseconds.
          If not specified defaults to 5.
        - wakeup-source: Boolean, button can wake-up the system.
+                        (Legacy property supported: "gpio-key,wakeup")
        - linux,can-disable: Boolean, indicates that button is connected
          to dedicated (not shared) interrupt which can be disabled to
          suppress events from the button.
index 4d86059c370c466a143d87fd6e6b183b5c132fc6..d0ea09ba249fc5ea484625564e81a815abd7f014 100644 (file)
@@ -20,6 +20,7 @@ Required Properties:
 Optional Properties:
 - linux,no-autorepeat: do no enable autorepeat feature.
 - wakeup-source:       use any event on keypad as wakeup event.
+                       (Legacy property supported: "linux,wakeup")
 - debounce-delay-ms:   debounce interval in milliseconds
 - col-scan-delay-us:   delay, measured in microseconds, that is needed
                        before we can scan keypad after activating column gpio
diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
new file mode 100644 (file)
index 0000000..488edcb
--- /dev/null
@@ -0,0 +1,28 @@
+* HID over I2C Device-Tree bindings
+
+HID over I2C provides support for various Human Interface Devices over the
+I2C bus. These devices can be for example touchpads, keyboards, touch screens
+or sensors.
+
+The specification has been written by Microsoft and is currently available here:
+http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
+
+If this binding is used, the kernel module i2c-hid will handle the communication
+with the device and the generic hid core layer will handle the protocol.
+
+Required properties:
+- compatible: must be "hid-over-i2c"
+- reg: i2c slave address
+- hid-descr-addr: HID descriptor address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: interrupt line
+
+Example:
+
+       i2c-hid-dev@2c {
+               compatible = "hid-over-i2c";
+               reg = <0x2c>;
+               hid-descr-addr = <0x0020>;
+               interrupt-parent = <&gpx3>;
+               interrupts = <3 2>;
+       };
index 0382b8bd69c63b2e821f3a976028384254c81437..1faa7292e21f5de0d2d439d2c554f24082457341 100644 (file)
@@ -29,7 +29,8 @@ matrix-keyboard bindings:
 - nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing
 - nvidia,repeat-delay-ms: delay in milliseconds before repeat starts
 - nvidia,ghost-filter: enable ghost filtering for this device
-- nvidia,wakeup-source: configure keyboard as a wakeup source for suspend/resume
+- wakeup-source: configure keyboard as a wakeup source for suspend/resume
+                (Legacy property supported: "nvidia,wakeup-source")
 
 Example:
 
index ee6215681182850d19d255fe7fce85f6bd1461c7..4a9dc6ba96b144b8667fc670524cec594f264b3d 100644 (file)
@@ -37,6 +37,7 @@ PROPERTIES
        Usage: optional
        Value type: <bool>
        Definition: use any event on keypad as wakeup event.
+                   (Legacy property supported: "linux,keypad-wakeup")
 
 - keypad,num-rows:
        Usage: required
index 331549593ed5e031ec696cad610f3347763574b7..de99cbbbf6da074fee825423636a0ca164364ee7 100644 (file)
@@ -14,7 +14,17 @@ Optional properties:
   device, hence no steps need to be passed.
 - rotary-encoder,rollover: Automatic rollove when the rotary value becomes
   greater than the specified steps or smaller than 0. For absolute axis only.
+- rotary-encoder,steps-per-period: Number of steps (stable states) per period.
+  The values have the following meaning:
+  1: Full-period mode (default)
+  2: Half-period mode
+  4: Quarter-period mode
+- wakeup-source: Boolean, rotary encoder can wake up the system.
+
+Deprecated properties:
 - rotary-encoder,half-period: Makes the driver work on half-period mode.
+  This property is deprecated. Instead, a 'steps-per-period ' value should
+  be used, such as "rotary-encoder,steps-per-period = <2>".
 
 See Documentation/input/rotary-encoder.txt for more information.
 
index 863e77f619dc6871cbf5dd6792daf38febcdfdaa..5305e74e57425135c069311b0db8671f992cda9e 100644 (file)
@@ -38,6 +38,7 @@ Required Board Specific Properties:
 
 Optional Properties:
 - wakeup-source: use any event on keypad as wakeup event.
+                (Legacy property supported: "linux,input-wakeup")
 
 Optional Properties specific to linux:
 - linux,keypad-no-autorepeat: do no enable autorepeat feature.
@@ -51,7 +52,7 @@ Example:
                samsung,keypad-num-rows = <2>;
                samsung,keypad-num-columns = <8>;
                linux,input-no-autorepeat;
-               linux,input-wakeup;
+               wakeup-source;
 
                pinctrl-names = "default";
                pinctrl-0 = <&keypad_rows &keypad_columns>;
index 76db96704a602e823fc6d09a04ddfd000a5949a7..f99528da1b1d4d7f354441d7c11e7dc2abe3c9ad 100644 (file)
@@ -5,6 +5,7 @@ There are 3 variants of the chip for various touch panel sizes
 FT5206GE1  2.8" .. 3.8"
 FT5306DE4  4.3" .. 7"
 FT5406EE8  7"   .. 8.9"
+FT5506EEG  7"   .. 8.9"
 
 The software interface is identical for all those chips, so that
 currently there is no need for the driver to distinguish between the
@@ -17,6 +18,7 @@ Required properties:
  - compatible:  "edt,edt-ft5206"
            or:  "edt,edt-ft5306"
            or:  "edt,edt-ft5406"
+           or:  "edt,edt-ft5506"
 
  - reg:         I2C slave address of the chip (0x38)
  - interrupt-parent: a phandle pointing to the interrupt controller
@@ -49,7 +51,7 @@ Example:
                pinctrl-names = "default";
                pinctrl-0 = <&edt_ft5x06_pins>;
                interrupt-parent = <&gpio2>;
-               interrupts = <5 0>;
-               reset-gpios = <&gpio2 6 1>;
-               wake-gpios = <&gpio4 9 0>;
+               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+               reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+               wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>;
        };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt
new file mode 100644 (file)
index 0000000..777521d
--- /dev/null
@@ -0,0 +1,35 @@
+* FocalTech FT6236 I2C touchscreen controller
+
+Required properties:
+ - compatible            : "focaltech,ft6236"
+ - reg                   : I2C slave address of the chip (0x38)
+ - interrupt-parent      : a phandle pointing to the interrupt controller
+                           serving the interrupt for this chip
+ - interrupts            : interrupt specification for the touch controller
+                           interrupt
+ - reset-gpios           : GPIO specification for the RSTN input
+ - touchscreen-size-x    : horizontal resolution of touchscreen (in pixels)
+ - touchscreen-size-y    : vertical resolution of touchscreen (in pixels)
+
+Optional properties:
+ - touchscreen-fuzz-x    : horizontal noise value of the absolute input
+                           device (in pixels)
+ - touchscreen-fuzz-y    : vertical noise value of the absolute input
+                           device (in pixels)
+ - touchscreen-inverted-x : X axis is inverted (boolean)
+ - touchscreen-inverted-y : Y axis is inverted (boolean)
+ - touchscreen-swapped-x-y: X and Y axis are swapped (boolean)
+                           Swapping is done after inverting the axis
+
+Example:
+
+       ft6x06@38 {
+               compatible = "focaltech,ft6236";
+               reg = <0x38>;
+               interrupt-parent = <&gpio>;
+               interrupts = <23 2>;
+               touchscreen-size-x = <320>;
+               touchscreen-size-y = <480>;
+               touchscreen-inverted-x;
+               touchscreen-swapped-x-y;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
new file mode 100644 (file)
index 0000000..7803e77
--- /dev/null
@@ -0,0 +1,123 @@
+* ARM Generic Interrupt Controller, version 3
+
+AArch64 SMP cores are often associated with a GICv3, providing Private
+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
+Software Generated Interrupts (SGI), and Locality-specific Peripheral
+Interrupts (LPI).
+
+Main node required properties:
+
+- compatible : should at least contain  "arm,gic-v3".
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. Must be a single cell with a value of at least 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts. Other values are reserved for future use.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987]. PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+       bits[3:0] trigger type and level flags.
+               1 = edge triggered
+               4 = level triggered
+
+  Cells 4 and beyond are reserved for future use. When the 1st cell
+  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
+  ignored. It is recommended that padding cells have a value of 0.
+
+- reg : Specifies base physical address(s) and size of the GIC
+  registers, in the following order:
+  - GIC Distributor interface (GICD)
+  - GIC Redistributors (GICR), one range per redistributor region
+  - GIC CPU interface (GICC)
+  - GIC Hypervisor interface (GICH)
+  - GIC Virtual CPU interface (GICV)
+
+  GICC, GICH and GICV are optional.
+
+- interrupts : Interrupt source of the VGIC maintenance interrupt.
+
+Optional
+
+- redistributor-stride : If using padding pages, specifies the stride
+  of consecutive redistributors. Must be a multiple of 64kB.
+
+- #redistributor-regions: The number of independent contiguous regions
+  occupied by the redistributors. Required if more than one such
+  region is present.
+
+Sub-nodes:
+
+GICv3 has one or more Interrupt Translation Services (ITS) that are
+used to route Message Signalled Interrupts (MSI) to the CPUs.
+
+These nodes must have the following properties:
+- compatible : Should at least contain  "arm,gic-v3-its".
+- msi-controller : Boolean property. Identifies the node as an MSI controller
+- #msi-cells: Must be <1>. The single msi-cell is the DeviceID of the device
+  which will generate the MSI.
+- reg: Specifies the base physical address and size of the ITS
+  registers.
+
+The main GIC node must contain the appropriate #address-cells,
+#size-cells and ranges properties for the reg property of all ITS
+nodes.
+
+Examples:
+
+       gic: interrupt-controller@2cf00000 {
+               compatible = "arm,gic-v3";
+               #interrupt-cells = <3>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               interrupt-controller;
+               reg = <0x0 0x2f000000 0 0x10000>,       // GICD
+                     <0x0 0x2f100000 0 0x200000>,      // GICR
+                     <0x0 0x2c000000 0 0x2000>,        // GICC
+                     <0x0 0x2c010000 0 0x2000>,        // GICH
+                     <0x0 0x2c020000 0 0x2000>;        // GICV
+               interrupts = <1 9 4>;
+
+               gic-its@2c200000 {
+                       compatible = "arm,gic-v3-its";
+                       msi-controller;
+                       #msi-cells = <1>;
+                       reg = <0x0 0x2c200000 0 0x200000>;
+               };
+       };
+
+       gic: interrupt-controller@2c010000 {
+               compatible = "arm,gic-v3";
+               #interrupt-cells = <3>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               interrupt-controller;
+               redistributor-stride = <0x0 0x40000>;   // 256kB stride
+               #redistributor-regions = <2>;
+               reg = <0x0 0x2c010000 0 0x10000>,       // GICD
+                     <0x0 0x2d000000 0 0x800000>,      // GICR 1: CPUs 0-31
+                     <0x0 0x2e000000 0 0x800000>;      // GICR 2: CPUs 32-63
+                     <0x0 0x2c040000 0 0x2000>,        // GICC
+                     <0x0 0x2c060000 0 0x2000>,        // GICH
+                     <0x0 0x2c080000 0 0x2000>;        // GICV
+               interrupts = <1 9 4>;
+
+               gic-its@2c200000 {
+                       compatible = "arm,gic-v3-its";
+                       msi-controller;
+                       #msi-cells = <1>;
+                       reg = <0x0 0x2c200000 0 0x200000>;
+               };
+
+               gic-its@2c400000 {
+                       compatible = "arm,gic-v3-its";
+                       msi-controller;
+                       #msi-cells = <1>;
+                       reg = <0x0 0x2c400000 0 0x200000>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
new file mode 100644 (file)
index 0000000..cc56021
--- /dev/null
@@ -0,0 +1,168 @@
+* ARM Generic Interrupt Controller
+
+ARM SMP cores are often associated with a GIC, providing per processor
+interrupts (PPI), shared processor interrupts (SPI) and software
+generated interrupts (SGI).
+
+Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
+Secondary GICs are cascaded into the upward interrupt controller and do not
+have PPIs or SGIs.
+
+Main node required properties:
+
+- compatible : should be one of:
+       "arm,arm1176jzf-devchip-gic"
+       "arm,arm11mp-gic"
+       "arm,cortex-a15-gic"
+       "arm,cortex-a7-gic"
+       "arm,cortex-a9-gic"
+       "arm,gic-400"
+       "arm,pl390"
+       "brcm,brahma-b15-gic"
+       "qcom,msm-8660-qgic"
+       "qcom,msm-qgic2"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source.  The type shall be a <u32> and the value shall be 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987].  PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+       bits[3:0] trigger type and level flags.
+               1 = low-to-high edge triggered
+               2 = high-to-low edge triggered (invalid for SPIs)
+               4 = active high level-sensitive
+               8 = active low level-sensitive (invalid for SPIs).
+       bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of
+       the 8 possible cpus attached to the GIC.  A bit set to '1' indicated
+       the interrupt is wired to that CPU.  Only valid for PPI interrupts.
+       Also note that the configurability of PPI interrupts is IMPLEMENTATION
+       DEFINED and as such not guaranteed to be present (most SoC available
+       in 2014 seem to ignore the setting of this flag and use the hardware
+       default value).
+
+- reg : Specifies base physical address(s) and size of the GIC registers. The
+  first region is the GIC distributor register base and size. The 2nd region is
+  the GIC cpu interface register base and size.
+
+Optional
+- interrupts   : Interrupt source of the parent interrupt controller on
+  secondary GICs, or VGIC maintenance interrupt on primary GIC (see
+  below).
+
+- cpu-offset   : per-cpu offset within the distributor and cpu interface
+  regions, used when the GIC doesn't have banked registers. The offset is
+  cpu-offset * cpu-nr.
+
+- clocks        : List of phandle and clock-specific pairs, one for each entry
+  in clock-names.
+- clock-names   : List of names for the GIC clock input(s). Valid clock names
+  depend on the GIC variant:
+       "ic_clk" (for "arm,arm11mp-gic")
+       "PERIPHCLKEN" (for "arm,cortex-a15-gic")
+       "PERIPHCLK", "PERIPHCLKEN" (for "arm,cortex-a9-gic")
+       "clk" (for "arm,gic-400")
+       "gclk" (for "arm,pl390")
+
+- power-domains : A phandle and PM domain specifier as defined by bindings of
+                 the power controller specified by phandle, used when the GIC
+                 is part of a Power or Clock Domain.
+
+
+Example:
+
+       intc: interrupt-controller@fff11000 {
+               compatible = "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <1>;
+               interrupt-controller;
+               reg = <0xfff11000 0x1000>,
+                     <0xfff10100 0x100>;
+       };
+
+
+* GIC virtualization extensions (VGIC)
+
+For ARM cores that support the virtualization extensions, additional
+properties must be described (they only exist if the GIC is the
+primary interrupt controller).
+
+Required properties:
+
+- reg : Additional regions specifying the base physical address and
+  size of the VGIC registers. The first additional region is the GIC
+  virtual interface control register base and size. The 2nd additional
+  region is the GIC virtual cpu interface register base and size.
+
+- interrupts : VGIC maintenance interrupt.
+
+Example:
+
+       interrupt-controller@2c001000 {
+               compatible = "arm,cortex-a15-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg = <0x2c001000 0x1000>,
+                     <0x2c002000 0x1000>,
+                     <0x2c004000 0x2000>,
+                     <0x2c006000 0x2000>;
+               interrupts = <1 9 0xf04>;
+       };
+
+
+* GICv2m extension for MSI/MSI-x support (Optional)
+
+Certain revisions of GIC-400 supports MSI/MSI-x via V2M register frame(s).
+This is enabled by specifying v2m sub-node(s).
+
+Required properties:
+
+- compatible       : The value here should contain "arm,gic-v2m-frame".
+
+- msi-controller    : Identifies the node as an MSI controller.
+
+- reg              : GICv2m MSI interface register base and size
+
+Optional properties:
+
+- arm,msi-base-spi  : When the MSI_TYPER register contains an incorrect
+                     value, this property should contain the SPI base of
+                     the MSI frame, overriding the HW value.
+
+- arm,msi-num-spis  : When the MSI_TYPER register contains an incorrect
+                     value, this property should contain the number of
+                     SPIs assigned to the frame, overriding the HW value.
+
+Example:
+
+       interrupt-controller@e1101000 {
+               compatible = "arm,gic-400";
+               #interrupt-cells = <3>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               interrupt-controller;
+               interrupts = <1 8 0xf04>;
+               ranges = <0 0 0 0xe1100000 0 0x100000>;
+               reg = <0x0 0xe1110000 0 0x01000>,
+                     <0x0 0xe112f000 0 0x02000>,
+                     <0x0 0xe1140000 0 0x10000>,
+                     <0x0 0xe1160000 0 0x10000>;
+               v2m0: v2m@0x8000 {
+                       compatible = "arm,gic-v2m-frame";
+                       msi-controller;
+                       reg = <0x0 0x80000 0 0x1000>;
+               };
+
+               ....
+
+               v2mN: v2m@0x9000 {
+                       compatible = "arm,gic-v2m-frame";
+                       msi-controller;
+                       reg = <0x0 0x90000 0 0x1000>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
new file mode 100644 (file)
index 0000000..c9cf605
--- /dev/null
@@ -0,0 +1,36 @@
+* ARM Versatile FPGA interrupt controller
+
+One or more FPGA IRQ controllers can be synthesized in an ARM reference board
+such as the Integrator or Versatile family. The output of these different
+controllers are OR:ed together and fed to the CPU tile's IRQ input. Each
+instance can handle up to 32 interrupts.
+
+Required properties:
+- compatible: "arm,versatile-fpga-irq"
+- interrupt-controller: Identifies the node as an interrupt controller
+- #interrupt-cells: The number of cells to define the interrupts.  Must be 1
+  as the FPGA IRQ controller has no configuration options for interrupt
+  sources.  The cell is a u32 and defines the interrupt number.
+- reg: The register bank for the FPGA interrupt controller.
+- clear-mask: a u32 number representing the mask written to clear all IRQs
+  on the controller at boot for example.
+- valid-mask: a u32 number representing a bit mask determining which of
+  the interrupts are valid. Unconnected/unused lines are set to 0, and
+  the system till not make it possible for devices to request these
+  interrupts.
+
+Example:
+
+pic: pic@14000000 {
+        compatible = "arm,versatile-fpga-irq";
+        #interrupt-cells = <1>;
+        interrupt-controller;
+        reg = <0x14000000 0x100>;
+        clear-mask = <0xffffffff>;
+        valid-mask = <0x003fffff>;
+};
+
+Optional properties:
+- interrupts: if the FPGA IRQ controller is cascaded, i.e. if its IRQ
+  output is simply connected to the input of another IRQ controller,
+  then the parent IRQ shall be specified in this property.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt
new file mode 100644 (file)
index 0000000..dd52721
--- /dev/null
@@ -0,0 +1,41 @@
+* ARM Vectored Interrupt Controller
+
+One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
+system for interrupt routing.  For multiple controllers they can either be
+nested or have the outputs wire-OR'd together.
+
+Required properties:
+
+- compatible : should be one of
+       "arm,pl190-vic"
+       "arm,pl192-vic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
+  the VIC has no configuration options for interrupt sources.  The cell is a u32
+  and defines the interrupt number.
+- reg : The register bank for the VIC.
+
+Optional properties:
+
+- interrupts : Interrupt source for parent controllers if the VIC is nested.
+- valid-mask : A one cell big bit mask of valid interrupt sources. Each bit
+  represents single interrupt source, starting from source 0 at LSb and ending
+  at source 31 at MSb. A bit that is set means that the source is wired and
+  clear means otherwise. If unspecified, defaults to all valid.
+- valid-wakeup-mask : A one cell big bit mask of interrupt sources that can be
+  configured as wake up source for the system. Order of bits is the same as for
+  valid-mask property. A set bit means that this interrupt source can be
+  configured as a wake up source for the system. If unspecied, defaults to all
+  interrupt sources configurable as wake up sources.
+
+Example:
+
+       vic0: interrupt-controller@60000 {
+               compatible = "arm,pl192-vic";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x60000 0x1000>;
+
+               valid-mask = <0xffffff7f>;
+               valid-wakeup-mask = <0x0000ff7f>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/axis,crisv32-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/axis,crisv32-intc.txt
new file mode 100644 (file)
index 0000000..e8b123b
--- /dev/null
@@ -0,0 +1,23 @@
+* CRISv32 Interrupt Controller
+
+Interrupt controller for the CRISv32 SoCs.
+
+Main node required properties:
+
+- compatible : should be:
+       "axis,crisv32-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+       intc: interrupt-controller {
+               compatible = "axis,crisv32-intc";
+               reg = <0xb001c000 0x1000>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+       };
+
+
diff --git a/Documentation/devicetree/bindings/interrupt-controller/img,meta-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/img,meta-intc.txt
new file mode 100644 (file)
index 0000000..80994ad
--- /dev/null
@@ -0,0 +1,82 @@
+* Meta External Trigger Controller Binding
+
+This binding specifies what properties must be available in the device tree
+representation of a Meta external trigger controller.
+
+Required properties:
+
+    - compatible: Specifies the compatibility list for the interrupt controller.
+      The type shall be <string> and the value shall include "img,meta-intc".
+
+    - num-banks: Specifies the number of interrupt banks (each of which can
+      handle 32 interrupt sources).
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an interrupt controller. No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source. The type shall be a <u32> and the value shall be 2.
+
+    - #address-cells: Specifies the number of cells needed to encode an
+      address. The type shall be <u32> and the value shall be 0. As such,
+      'interrupt-map' nodes do not have to specify a parent unit address.
+
+Optional properties:
+
+    - no-mask: The controller doesn't have any mask registers.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+
+    - <2nd-cell>: The Linux interrupt flags containing level-sense information,
+                  encoded as follows:
+                    1 = edge triggered
+                    4 = level-sensitive
+
+* Examples
+
+Example 1:
+
+       /*
+        * Meta external trigger block
+        */
+       intc: intc {
+               // This is an interrupt controller node.
+               interrupt-controller;
+
+               // No address cells so that 'interrupt-map' nodes which
+               // reference this interrupt controller node do not need a parent
+               // address specifier.
+               #address-cells = <0>;
+
+               // Two cells to encode interrupt sources.
+               #interrupt-cells = <2>;
+
+               // Number of interrupt banks
+               num-banks = <2>;
+
+               // No HWMASKEXT is available (specify on Chorus2 and Comet ES1)
+               no-mask;
+
+               // Compatible with Meta hardware trigger block.
+               compatible = "img,meta-intc";
+       };
+
+Example 2:
+
+       /*
+        * An interrupt generating device that is wired to a Meta external
+        * trigger block.
+        */
+       uart1: uart@0x02004c00 {
+               // Interrupt source '5' that is level-sensitive.
+               // Note that there are only two cells as specified in the
+               // interrupt parent's '#interrupt-cells' property.
+               interrupts = <5 4 /* level */>;
+
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&intc>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/img,pdc-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/img,pdc-intc.txt
new file mode 100644 (file)
index 0000000..a691185
--- /dev/null
@@ -0,0 +1,105 @@
+* ImgTec Powerdown Controller (PDC) Interrupt Controller Binding
+
+This binding specifies what properties must be available in the device tree
+representation of a PDC IRQ controller. This has a number of input interrupt
+lines which can wake the system, and are passed on through output interrupt
+lines.
+
+Required properties:
+
+    - compatible: Specifies the compatibility list for the interrupt controller.
+      The type shall be <string> and the value shall include "img,pdc-intc".
+
+    - reg: Specifies the base PDC physical address(s) and size(s) of the
+      addressable register space. The type shall be <prop-encoded-array>.
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an interrupt controller. No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source. The type shall be a <u32> and the value shall be 2.
+
+    - num-perips: Number of waking peripherals.
+
+    - num-syswakes: Number of SysWake inputs.
+
+    - interrupts: List of interrupt specifiers. The first specifier shall be the
+      shared SysWake interrupt, and remaining specifies shall be PDC peripheral
+      interrupts in order.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+                    0-7:  Peripheral interrupts
+                    8-15: SysWake interrupts
+
+    - <2nd-cell>: The level-sense information, encoded using the Linux interrupt
+                  flags as follows (only 4 valid for peripheral interrupts):
+                    0 = none (decided by software)
+                    1 = low-to-high edge triggered
+                    2 = high-to-low edge triggered
+                    3 = both edge triggered
+                    4 = active-high level-sensitive (required for perip irqs)
+                    8 = active-low level-sensitive
+
+* Examples
+
+Example 1:
+
+       /*
+        * TZ1090 PDC block
+        */
+       pdc: pdc@0x02006000 {
+               // This is an interrupt controller node.
+               interrupt-controller;
+
+               // Three cells to encode interrupt sources.
+               #interrupt-cells = <2>;
+
+               // Offset address of 0x02006000 and size of 0x1000.
+               reg = <0x02006000 0x1000>;
+
+               // Compatible with Meta hardware trigger block.
+               compatible = "img,pdc-intc";
+
+               // Three peripherals are connected.
+               num-perips = <3>;
+
+               // Four SysWakes are connected.
+               num-syswakes = <4>;
+
+               interrupts = <18 4 /* level */>, /* Syswakes */
+                            <30 4 /* level */>, /* Peripheral 0 (RTC) */
+                            <29 4 /* level */>, /* Peripheral 1 (IR) */
+                            <31 4 /* level */>; /* Peripheral 2 (WDT) */
+       };
+
+Example 2:
+
+       /*
+        * An SoC peripheral that is wired through the PDC.
+        */
+       rtc0 {
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&pdc>;
+
+               // Interrupt source Peripheral 0
+               interrupts = <0   /* Peripheral 0 (RTC) */
+                             4>  /* IRQ_TYPE_LEVEL_HIGH */
+       };
+
+Example 3:
+
+       /*
+        * An interrupt generating device that is wired to a SysWake pin.
+        */
+       touchscreen0 {
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&pdc>;
+
+               // Interrupt source SysWake 0 that is active-low level-sensitive
+               interrupts = <8 /* SysWake0 */
+                             8 /* IRQ_TYPE_LEVEL_LOW */>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt b/Documentation/devicetree/bindings/interrupt-controller/intel,ce4100-ioapic.txt
new file mode 100644 (file)
index 0000000..7d19f49
--- /dev/null
@@ -0,0 +1,26 @@
+Interrupt chips
+---------------
+
+* Intel I/O Advanced Programmable Interrupt Controller (IO APIC)
+
+  Required properties:
+  --------------------
+     compatible = "intel,ce4100-ioapic";
+     #interrupt-cells = <2>;
+
+  Device's interrupt property:
+
+     interrupts = <P S>;
+
+  The first number (P) represents the interrupt pin which is wired to the
+  IO APIC. The second number (S) represents the sense of interrupt which
+  should be configured and can be one of:
+    0 - Edge Rising
+    1 - Level Low
+    2 - Level High
+    3 - Edge Falling
+
+* Local APIC
+  Required property:
+
+     compatible = "intel,ce4100-lapic";
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt
new file mode 100644 (file)
index 0000000..afef6a8
--- /dev/null
@@ -0,0 +1,32 @@
++Mediatek 65xx/67xx/81xx sysirq
+
+Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI
+interrupt.
+
+Required properties:
+- compatible: should be one of:
+       "mediatek,mt8173-sysirq"
+       "mediatek,mt8135-sysirq"
+       "mediatek,mt8127-sysirq"
+       "mediatek,mt6795-sysirq"
+       "mediatek,mt6592-sysirq"
+       "mediatek,mt6589-sysirq"
+       "mediatek,mt6582-sysirq"
+       "mediatek,mt6580-sysirq"
+       "mediatek,mt6577-sysirq"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Use the same format as specified by GIC in
+  Documentation/devicetree/bindings/arm/gic.txt
+- interrupt-parent: phandle of irq parent for sysirq. The parent must
+  use the same interrupt-cells format as GIC.
+- reg: Physical base address of the intpol registers and length of memory
+  mapped region.
+
+Example:
+       sysirq: interrupt-controller@10200100 {
+               compatible = "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq";
+               interrupt-controller;
+               #interrupt-cells = <3>;
+               interrupt-parent = <&gic>;
+               reg = <0 0x10200100 0 0x1c>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/mrvl,intc.txt
new file mode 100644 (file)
index 0000000..8b53273
--- /dev/null
@@ -0,0 +1,60 @@
+* Marvell MMP Interrupt controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
+  "mrvl,mmp2-mux-intc"
+- reg : Address and length of the register set of the interrupt controller.
+  If the interrupt controller is intc, address and length means the range
+  of the whold interrupt controller. If the interrupt controller is mux-intc,
+  address and length means one register. Since address of mux-intc is in the
+  range of intc. mux-intc is secondary interrupt controller.
+- reg-names : Name of the register set of the interrupt controller. It's
+  only required in mux-intc interrupt controller.
+- interrupts : Should be the port interrupt shared by mux interrupts. It's
+  only required in mux-intc interrupt controller.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source.
+- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt
+  controller.
+- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
+  detection first.
+
+Example:
+       intc: interrupt-controller@d4282000 {
+               compatible = "mrvl,mmp2-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0xd4282000 0x1000>;
+               mrvl,intc-nr-irqs = <64>;
+       };
+
+       intcmux4@d4282150 {
+               compatible = "mrvl,mmp2-mux-intc";
+               interrupts = <4>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x150 0x4>, <0x168 0x4>;
+               reg-names = "mux status", "mux mask";
+               mrvl,intc-nr-irqs = <2>;
+       };
+
+* Marvell Orion Interrupt controller
+
+Required properties
+- compatible :  Should be "marvell,orion-intc".
+- #interrupt-cells: Specifies the number of cells needed to encode an
+  interrupt source. Supported value is <1>.
+- interrupt-controller : Declare this node to be an interrupt controller.
+- reg : Interrupt mask address. A list of 4 byte ranges, one per controller.
+        One entry in the list represents 32 interrupts.
+
+Example:
+
+       intc: interrupt-controller {
+               compatible = "marvell,orion-intc", "marvell,intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+                reg = <0xfed20204 0x04>,
+                     <0xfed20214 0x04>;
+        };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/nxp,lpc3220-mic.txt b/Documentation/devicetree/bindings/interrupt-controller/nxp,lpc3220-mic.txt
new file mode 100644 (file)
index 0000000..539adca
--- /dev/null
@@ -0,0 +1,38 @@
+* NXP LPC32xx Main Interrupt Controller
+  (MIC, including SIC1 and SIC2 secondary controllers)
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-mic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: Empty for the interrupt controller itself
+- #interrupt-cells: The number of cells to define the interrupts. Should be 2.
+  The first cell is the IRQ number
+  The second cell is used to specify mode:
+      1 = low-to-high edge triggered
+      2 = high-to-low edge triggered
+      4 = active high level-sensitive
+      8 = active low level-sensitive
+      Default for internal sources should be set to 4 (active high).
+- reg: Should contain MIC registers location and length
+
+Examples:
+       /*
+        * MIC
+        */
+       mic: interrupt-controller@40008000 {
+               compatible = "nxp,lpc3220-mic";
+               interrupt-controller;
+               interrupt-parent;
+               #interrupt-cells = <2>;
+               reg = <0x40008000 0xC000>;
+       };
+
+       /*
+        * ADC
+        */
+       adc@40048000 {
+               compatible = "nxp,lpc3220-adc";
+               reg = <0x40048000 0x1000>;
+               interrupt-parent = <&mic>;
+               interrupts = <39 4>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/open-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/open-pic.txt
new file mode 100644 (file)
index 0000000..909a902
--- /dev/null
@@ -0,0 +1,98 @@
+* Open PIC Binding
+
+This binding specifies what properties must be available in the device tree
+representation of an Open PIC compliant interrupt controller.  This binding is
+based on the binding defined for Open PIC in [1] and is a superset of that
+binding.
+
+Required properties:
+
+  NOTE: Many of these descriptions were paraphrased here from [1] to aid
+        readability.
+
+    - compatible: Specifies the compatibility list for the PIC.  The type
+      shall be <string> and the value shall include "open-pic".
+
+    - reg: Specifies the base physical address(s) and size(s) of this
+      PIC's addressable register space.  The type shall be <prop-encoded-array>.
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an Open PIC.  No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source.  The type shall be a <u32> and the value shall be 2.
+
+    - #address-cells: Specifies the number of cells needed to encode an
+      address.  The type shall be <u32> and the value shall be 0.  As such,
+      'interrupt-map' nodes do not have to specify a parent unit address.
+
+Optional properties:
+
+    - pic-no-reset: The presence of this property indicates that the PIC
+      shall not be reset during runtime initialization.  No property value shall
+      be defined.  The presence of this property also mandates that any
+      initialization related to interrupt sources shall be limited to sources
+      explicitly referenced in the device tree.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as
+  follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+
+    - <2nd-cell>: The level-sense information, encoded as follows:
+                    0 = low-to-high edge triggered
+                    1 = active low level-sensitive
+                    2 = active high level-sensitive
+                    3 = high-to-low edge triggered
+
+* Examples
+
+Example 1:
+
+       /*
+        * An Open PIC interrupt controller
+        */
+       mpic: pic@40000 {
+               // This is an interrupt controller node.
+               interrupt-controller;
+
+               // No address cells so that 'interrupt-map' nodes which reference
+               // this Open PIC node do not need a parent address specifier.
+               #address-cells = <0>;
+
+               // Two cells to encode interrupt sources.
+               #interrupt-cells = <2>;
+
+               // Offset address of 0x40000 and size of 0x40000.
+               reg = <0x40000 0x40000>;
+
+               // Compatible with Open PIC.
+               compatible = "open-pic";
+
+               // The PIC shall not be reset.
+               pic-no-reset;
+       };
+
+Example 2:
+
+       /*
+        * An interrupt generating device that is wired to an Open PIC.
+        */
+       serial0: serial@4500 {
+               // Interrupt source '42' that is active high level-sensitive.
+               // Note that there are only two cells as specified in the interrupt
+               // parent's '#interrupt-cells' property.
+               interrupts = <42 2>;
+
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&mpic>;
+       };
+
+* References
+
+[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform
+    Requirements (ePAPR), Version 1.0, July 2008.
+    (http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf)
+
diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,exynos4210-combiner.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,exynos4210-combiner.txt
new file mode 100644 (file)
index 0000000..9e5f734
--- /dev/null
@@ -0,0 +1,52 @@
+* Samsung Exynos Interrupt Combiner Controller
+
+Samsung's Exynos4 architecture includes a interrupt combiner controller which
+can combine interrupt sources as a group and provide a single interrupt request
+for the group. The interrupt request from each group are connected to a parent
+interrupt controller, such as GIC in case of Exynos4210.
+
+The interrupt combiner controller consists of multiple combiners. Up to eight
+interrupt sources can be connected to a combiner. The combiner outputs one
+combined interrupt for its eight interrupt sources. The combined interrupt
+is usually connected to a parent interrupt controller.
+
+A single node in the device tree is used to describe the interrupt combiner
+controller module (which includes multiple combiners). A combiner in the
+interrupt controller module shares config/control registers with other
+combiners. For example, a 32-bit interrupt enable/disable config register
+can accommodate up to 4 interrupt combiners (with each combiner supporting
+up to 8 interrupt sources).
+
+Required properties:
+- compatible: should be "samsung,exynos4210-combiner".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- #interrupt-cells: should be <2>. The meaning of the cells are
+       * First Cell: Combiner Group Number.
+       * Second Cell: Interrupt number within the group.
+- reg: Base address and size of interrupt combiner registers.
+- interrupts: The list of interrupts generated by the combiners which are then
+    connected to a parent interrupt controller. The format of the interrupt
+    specifier depends in the interrupt parent controller.
+
+Optional properties:
+- samsung,combiner-nr: The number of interrupt combiners supported. If this
+  property is not specified, the default number of combiners is assumed
+  to be 16.
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.
+
+
+Example:
+
+       The following is a an example from the Exynos4210 SoC dtsi file.
+
+       combiner:interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               reg = <0x10440000 0x1000>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,arc700-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,arc700-intc.txt
new file mode 100644 (file)
index 0000000..9a5d562
--- /dev/null
@@ -0,0 +1,24 @@
+* ARC700 incore Interrupt Controller
+
+  The core interrupt controller provides 32 prioritised interrupts (2 levels)
+  to ARC700 core.
+
+Properties:
+
+- compatible: "snps,arc700-intc"
+- interrupt-controller: This is an interrupt controller.
+- #interrupt-cells: Must be <1>.
+
+  Single Cell "interrupts" property of a device specifies the IRQ number
+  between 0 to 31
+
+  intc accessed via the special ARC AUX register interface, hence "reg" property
+  is not specified.
+
+Example:
+
+       intc: interrupt-controller {
+               compatible = "snps,arc700-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt
new file mode 100644 (file)
index 0000000..0dcb7c7
--- /dev/null
@@ -0,0 +1,46 @@
+* ARC-HS Interrupt Distribution Unit
+
+  This optional 2nd level interrupt controller can be used in SMP configurations for
+  dynamic IRQ routing, load balancing of common/external IRQs towards core intc.
+
+Properties:
+
+- compatible: "snps,archs-idu-intc"
+- interrupt-controller: This is an interrupt controller.
+- interrupt-parent: <reference to parent core intc>
+- #interrupt-cells: Must be <2>.
+- interrupts: <...> specifies the upstream core irqs
+
+  First cell specifies the "common" IRQ from peripheral to IDU
+  Second cell specifies the irq distribution mode to cores
+     0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3
+
+  intc accessed via the special ARC AUX register interface, hence "reg" property
+  is not specified.
+
+Example:
+       core_intc: core-interrupt-controller {
+               compatible = "snps,archs-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+       };
+
+       idu_intc: idu-interrupt-controller {
+               compatible = "snps,archs-idu-intc";
+               interrupt-controller;
+               interrupt-parent = <&core_intc>;
+
+               /*
+                * <hwirq  distribution>
+                * distribution: 0=RR; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3
+                */
+               #interrupt-cells = <2>;
+
+               /* upstream core irqs: downstream these are "COMMON" irq 0,1..  */
+               interrupts = <24 25 26 27 28 29 30 31>;
+       };
+
+       some_device: serial@c0fc1000 {
+               interrupt-parent = <&idu_intc>;
+               interrupts = <0 0>;     /* upstream idu IRQ #24, Round Robin */
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-intc.txt
new file mode 100644 (file)
index 0000000..69f326d
--- /dev/null
@@ -0,0 +1,22 @@
+* ARC-HS incore Interrupt Controller (Provided by cores implementing ARCv2 ISA)
+
+Properties:
+
+- compatible: "snps,archs-intc"
+- interrupt-controller: This is an interrupt controller.
+- #interrupt-cells: Must be <1>.
+
+  Single Cell "interrupts" property of a device specifies the IRQ number
+  between 16 to 256
+
+  intc accessed via the special ARC AUX register interface, hence "reg" property
+  is not specified.
+
+Example:
+
+       intc: interrupt-controller {
+               compatible = "snps,archs-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               interrupts = <16 17 18 19 20 21 22 23 24 25>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,spear3xx-shirq.txt b/Documentation/devicetree/bindings/interrupt-controller/st,spear3xx-shirq.txt
new file mode 100644 (file)
index 0000000..715a013
--- /dev/null
@@ -0,0 +1,48 @@
+* SPEAr Shared IRQ layer (shirq)
+
+SPEAr3xx architecture includes shared/multiplexed irqs for certain set
+of devices. The multiplexor provides a single interrupt to parent
+interrupt controller (VIC) on behalf of a group of devices.
+
+There can be multiple groups available on SPEAr3xx variants but not
+exceeding 4. The number of devices in a group can differ, further they
+may share same set of status/mask registers spanning across different
+bit masks. Also in some cases the group may not have enable or other
+registers. This makes software little complex.
+
+A single node in the device tree is used to describe the shared
+interrupt multiplexor (one node for all groups). A group in the
+interrupt controller shares config/control registers with other groups.
+For example, a 32-bit interrupt enable/disable config register can
+accommodate up to 4 interrupt groups.
+
+Required properties:
+  - compatible: should be, either of
+     - "st,spear300-shirq"
+     - "st,spear310-shirq"
+     - "st,spear320-shirq"
+  - interrupt-controller: Identifies the node as an interrupt controller.
+  - #interrupt-cells: should be <1> which basically contains the offset
+    (starting from 0) of interrupts for all the groups.
+  - reg: Base address and size of shirq registers.
+  - interrupts: The list of interrupts generated by the groups which are
+    then connected to a parent interrupt controller. Each group is
+    associated with one of the interrupts, hence number of interrupts (to
+    parent) is equal to number of groups. The format of the interrupt
+    specifier depends in the interrupt parent controller.
+
+  Optional properties:
+  - interrupt-parent: pHandle of the parent interrupt controller, if not
+    inherited from the parent node.
+
+Example:
+
+The following is an example from the SPEAr320 SoC dtsi file.
+
+shirq: interrupt-controller@0xb3000000 {
+       compatible = "st,spear320-shirq";
+       reg = <0xb3000000 0x1000>;
+       interrupts = <28 29 30 1>;
+       #interrupt-cells = <1>;
+       interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,c64x+megamod-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,c64x+megamod-pic.txt
new file mode 100644 (file)
index 0000000..42bb796
--- /dev/null
@@ -0,0 +1,104 @@
+C6X Interrupt Chips
+-------------------
+
+* C64X+ Core Interrupt Controller
+
+  The core interrupt controller provides 16 prioritized interrupts to the
+  C64X+ core. Priority 0 and 1 are used for reset and NMI respectively.
+  Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt
+  sources coming from outside the core.
+
+  Required properties:
+  --------------------
+  - compatible: Should be "ti,c64x+core-pic";
+  - #interrupt-cells: <1>
+
+  Interrupt Specifier Definition
+  ------------------------------
+  Single cell specifying the core interrupt priority level (4-15) where
+  4 is highest priority and 15 is lowest priority.
+
+  Example
+  -------
+  core_pic: interrupt-controller@0 {
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       compatible = "ti,c64x+core-pic";
+  };
+
+
+
+* C64x+ Megamodule Interrupt Controller
+
+  The megamodule PIC consists of four interrupt mupliplexers each of which
+  combine up to 32 interrupt inputs into a single interrupt output which
+  may be cascaded into the core interrupt controller. The megamodule PIC
+  has a total of 12 outputs cascading into the core interrupt controller.
+  One for each core interrupt priority level. In addition to the combined
+  interrupt sources, individual megamodule interrupts may be cascaded to
+  the core interrupt controller. When an individual interrupt is cascaded,
+  it is no longer handled through a megamodule interrupt combiner and is
+  considered to have the core interrupt controller as the parent.
+
+  Required properties:
+  --------------------
+  - compatible: "ti,c64x+megamod-pic"
+  - interrupt-controller
+  - #interrupt-cells: <1>
+  - reg: base address and size of register area
+  - interrupt-parent: must be core interrupt controller
+  - interrupts: This should have four cells; one for each interrupt combiner.
+                The cells contain the core priority interrupt to which the
+                corresponding combiner output is wired.
+
+  Optional properties:
+  --------------------
+  - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core
+                             priority interrupts. The first cell corresponds to
+                             core priority 4 and the last cell corresponds to
+                             core priority 15. The value of each cell is the
+                             megamodule interrupt source which is MUXed to
+                             the core interrupt corresponding to the cell
+                             position. Allowed values are 4 - 127. Mapping for
+                             interrupts 0 - 3 (combined interrupt sources) are
+                             ignored.
+
+  Interrupt Specifier Definition
+  ------------------------------
+  Single cell specifying the megamodule interrupt source (4-127). Note that
+  interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will
+  use the core interrupt controller as their parent and the specifier will
+  be the core priority level, not the megamodule interrupt number.
+
+  Examples
+  --------
+  megamod_pic: interrupt-controller@1800000 {
+       compatible = "ti,c64x+megamod-pic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       reg = <0x1800000 0x1000>;
+       interrupt-parent = <&core_pic>;
+       interrupts = < 12 13 14 15 >;
+  };
+
+  This is a minimal example where all individual interrupts go through a
+  combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped
+  to interrupt 13, etc.
+
+
+  megamod_pic: interrupt-controller@1800000 {
+       compatible = "ti,c64x+megamod-pic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       reg = <0x1800000 0x1000>;
+       interrupt-parent = <&core_pic>;
+       interrupts = < 12 13 14 15 >;
+       ti,c64x+megamod-pic-mux = <  0  0  0  0
+                                    32  0  0  0
+                                     0  0  0  0 >;
+  };
+
+  This the same as the first example except that megamodule interrupt 32 is
+  mapped directly to core priority interrupt 8. The node using this interrupt
+  must set the core controller as its interrupt parent and use 8 in the
+  interrupt specifier value.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,cp-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,cp-intc.txt
new file mode 100644 (file)
index 0000000..597e8a0
--- /dev/null
@@ -0,0 +1,27 @@
+* TI Common Platform Interrupt Controller
+
+Common Platform Interrupt Controller (cp_intc) is used on
+OMAP-L1x SoCs and can support several configurable number
+of interrupts.
+
+Main node required properties:
+
+- compatible : should be:
+       "ti,cp-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+
+  The cell contains the interrupt number in the range [0-128].
+- ti,intc-size: Number of interrupts handled by the interrupt controller.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+       intc: interrupt-controller@1 {
+               compatible = "ti,cp-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               ti,intc-size = <101>;
+               reg = <0xfffee000 0x2000>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,omap2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,omap2-intc.txt
new file mode 100644 (file)
index 0000000..f2583e6
--- /dev/null
@@ -0,0 +1,27 @@
+* OMAP Interrupt Controller
+
+OMAP2/3 are using a TI interrupt controller that can support several
+configurable number of interrupts.
+
+Main node required properties:
+
+- compatible : should be:
+       "ti,omap2-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+
+  The cell contains the interrupt number in the range [0-128].
+- ti,intc-size: Number of interrupts handled by the interrupt controller.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+       intc: interrupt-controller@1 {
+               compatible = "ti,omap2-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               ti,intc-size = <96>;
+               reg = <0x48200000 0x1000>;
+       };
+
diff --git a/Documentation/devicetree/bindings/interrupt-controller/via,vt8500-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/via,vt8500-intc.txt
new file mode 100644 (file)
index 0000000..0a4ce10
--- /dev/null
@@ -0,0 +1,16 @@
+VIA/Wondermedia VT8500 Interrupt Controller
+-----------------------------------------------------
+
+Required properties:
+- compatible : "via,vt8500-intc"
+- reg : Should contain 1 register ranges(address and length)
+- #interrupt-cells : should be <1>
+
+Example:
+
+       intc: interrupt-controller@d8140000 {
+               compatible = "via,vt8500-intc";
+               interrupt-controller;
+               reg = <0xd8140000 0x10000>;
+               #interrupt-cells = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/88pm860x.txt b/Documentation/devicetree/bindings/leds/backlight/88pm860x.txt
new file mode 100644 (file)
index 0000000..261df27
--- /dev/null
@@ -0,0 +1,15 @@
+88pm860x-backlight bindings
+
+Optional properties:
+  - marvell,88pm860x-iset: Current supplies on backlight device.
+  - marvell,88pm860x-pwm: PWM frequency on backlight device.
+
+Example:
+
+       backlights {
+               backlight-0 {
+                       marvell,88pm860x-iset = <4>;
+                       marvell,88pm860x-pwm = <3>;
+               };
+               backlight-2 {
+               };
diff --git a/Documentation/devicetree/bindings/leds/backlight/gpio-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/gpio-backlight.txt
new file mode 100644 (file)
index 0000000..321be66
--- /dev/null
@@ -0,0 +1,16 @@
+gpio-backlight bindings
+
+Required properties:
+  - compatible: "gpio-backlight"
+  - gpios: describes the gpio that is used for enabling/disabling the backlight.
+    refer to bindings/gpio/gpio.txt for more details.
+
+Optional properties:
+  - default-on: enable the backlight at boot.
+
+Example:
+       backlight {
+               compatible = "gpio-backlight";
+               gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+               default-on;
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/lp855x.txt b/Documentation/devicetree/bindings/leds/backlight/lp855x.txt
new file mode 100644 (file)
index 0000000..0a3ecbc
--- /dev/null
@@ -0,0 +1,70 @@
+lp855x bindings
+
+Required properties:
+  - compatible: "ti,lp8550", "ti,lp8551", "ti,lp8552", "ti,lp8553",
+                "ti,lp8555", "ti,lp8556", "ti,lp8557"
+  - reg: I2C slave address (u8)
+  - dev-ctrl: Value of DEVICE CONTROL register (u8). It depends on the device.
+
+Optional properties:
+  - bl-name: Backlight device name (string)
+  - init-brt: Initial value of backlight brightness (u8)
+  - pwm-period: PWM period value. Set only PWM input mode used (u32)
+  - rom-addr: Register address of ROM area to be updated (u8)
+  - rom-val: Register value to be updated (u8)
+  - power-supply: Regulator which controls the 3V rail
+
+Example:
+
+       /* LP8555 */
+       backlight@2c {
+               compatible = "ti,lp8555";
+               reg = <0x2c>;
+
+               dev-ctrl = /bits/ 8 <0x00>;
+               pwm-period = <10000>;
+
+               /* 4V OV, 4 output LED0 string enabled */
+               rom_14h {
+                       rom-addr = /bits/ 8 <0x14>;
+                       rom-val = /bits/ 8 <0xcf>;
+               };
+
+               /* Heavy smoothing, 24ms ramp time step */
+               rom_15h {
+                       rom-addr = /bits/ 8 <0x15>;
+                       rom-val = /bits/ 8 <0xc7>;
+               };
+
+               /* 4 output LED1 string enabled */
+               rom_19h {
+                       rom-addr = /bits/ 8 <0x19>;
+                       rom-val = /bits/ 8 <0x0f>;
+               };
+       };
+
+       /* LP8556 */
+       backlight@2c {
+               compatible = "ti,lp8556";
+               reg = <0x2c>;
+
+               bl-name = "lcd-bl";
+               dev-ctrl = /bits/ 8 <0x85>;
+               init-brt = /bits/ 8 <0x10>;
+       };
+
+       /* LP8557 */
+       backlight@2c {
+               compatible = "ti,lp8557";
+               reg = <0x2c>;
+               power-supply = <&backlight_vdd>;
+
+               dev-ctrl = /bits/ 8 <0x41>;
+               init-brt = /bits/ 8 <0x0a>;
+
+               /* 4V OV, 4 output LED string enabled */
+               rom_14h {
+                       rom-addr = /bits/ 8 <0x14>;
+                       rom-val = /bits/ 8 <0xcf>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/max8925-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/max8925-backlight.txt
new file mode 100644 (file)
index 0000000..b4cffda
--- /dev/null
@@ -0,0 +1,10 @@
+88pm860x-backlight bindings
+
+Optional properties:
+  - maxim,max8925-dual-string: whether support dual string
+
+Example:
+
+       backlights {
+               maxim,max8925-dual-string = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt b/Documentation/devicetree/bindings/leds/backlight/pm8941-wled.txt
new file mode 100644 (file)
index 0000000..e5b294d
--- /dev/null
@@ -0,0 +1,42 @@
+Binding for Qualcomm PM8941 WLED driver
+
+Required properties:
+- compatible: should be "qcom,pm8941-wled"
+- reg: slave address
+
+Optional properties:
+- default-brightness: brightness value on boot, value from: 0-4095
+       default: 2048
+- label: The name of the backlight device
+- qcom,cs-out: bool; enable current sink output
+- qcom,cabc: bool; enable content adaptive backlight control
+- qcom,ext-gen: bool; use externally generated modulator signal to dim
+- qcom,current-limit: mA; per-string current limit; value from 0 to 25
+       default: 20mA
+- qcom,current-boost-limit: mA; boost current limit; one of:
+       105, 385, 525, 805, 980, 1260, 1400, 1680
+       default: 805mA
+- qcom,switching-freq: kHz; switching frequency; one of:
+       600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
+       1600, 1920, 2400, 3200, 4800, 9600,
+       default: 1600kHz
+- qcom,ovp: V; Over-voltage protection limit; one of:
+       27, 29, 32, 35
+       default: 29V
+- qcom,num-strings: #; number of led strings attached; value from 1 to 3
+       default: 2
+
+Example:
+
+pm8941-wled@d800 {
+       compatible = "qcom,pm8941-wled";
+       reg = <0xd800>;
+       label = "backlight";
+
+       qcom,cs-out;
+       qcom,current-limit = <20>;
+       qcom,current-boost-limit = <805>;
+       qcom,switching-freq = <1600>;
+       qcom,ovp = <29>;
+       qcom,num-strings = <2>;
+};
diff --git a/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt
new file mode 100644 (file)
index 0000000..764db86
--- /dev/null
@@ -0,0 +1,35 @@
+pwm-backlight bindings
+
+Required properties:
+  - compatible: "pwm-backlight"
+  - pwms: OF device-tree PWM specification (see PWM binding[0])
+  - brightness-levels: Array of distinct brightness levels. Typically these
+      are in the range from 0 to 255, but any range starting at 0 will do.
+      The actual brightness level (PWM duty cycle) will be interpolated
+      from these values. 0 means a 0% duty cycle (darkest/off), while the
+      last value in the array represents a 100% duty cycle (brightest).
+  - default-brightness-level: the default brightness level (index into the
+      array defined by the "brightness-levels" property)
+  - power-supply: regulator for supply voltage
+
+Optional properties:
+  - pwm-names: a list of names for the PWM devices specified in the
+               "pwms" property (see PWM binding[0])
+  - enable-gpios: contains a single GPIO specifier for the GPIO which enables
+                  and disables the backlight (see GPIO binding[1])
+
+[0]: Documentation/devicetree/bindings/pwm/pwm.txt
+[1]: Documentation/devicetree/bindings/gpio/gpio.txt
+
+Example:
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 0 5000000>;
+
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+
+               power-supply = <&vdd_bl_reg>;
+               enable-gpios = <&gpio 58 0>;
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/sky81452-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/sky81452-backlight.txt
new file mode 100644 (file)
index 0000000..8bf2940
--- /dev/null
@@ -0,0 +1,29 @@
+SKY81452-backlight bindings
+
+Required properties:
+- compatible           : Must be "skyworks,sky81452-backlight"
+
+Optional properties:
+- name                 : Name of backlight device. Default is 'lcd-backlight'.
+- gpios                        : GPIO to use to EN pin.
+                       See Documentation/devicetree/bindings/gpio/gpio.txt
+- led-sources          : List of enabled channels from 0 to 5.
+                       See Documentation/devicetree/bindings/leds/common.txt
+- skyworks,ignore-pwm  : Ignore both PWM input
+- skyworks,dpwm-mode   : Enable DPWM dimming mode, otherwise Analog dimming.
+- skyworks,phase-shift : Enable phase shift mode
+- skyworks,short-detection-threshold-volt
+                       : It should be one of 4, 5, 6 and 7V.
+- skyworks,current-limit-mA
+                       : It should be 2300mA or 2750mA.
+
+Example:
+
+       backlight {
+               compatible = "skyworks,sky81452-backlight";
+               name = "pwm-backlight";
+               led-sources = <0 1 2 5>;
+               skyworks,ignore-pwm;
+               skyworks,phase-shift;
+               skyworks,current-limit-mA = <2300>;
+       };
diff --git a/Documentation/devicetree/bindings/leds/backlight/tps65217-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/tps65217-backlight.txt
new file mode 100644 (file)
index 0000000..5fb9279
--- /dev/null
@@ -0,0 +1,27 @@
+TPS65217 family of regulators
+
+The TPS65217 chip contains a boost converter and current sinks which can be
+used to drive LEDs for use as backlights.
+
+Required properties:
+- compatible: "ti,tps65217"
+- reg: I2C slave address
+- backlight: node for specifying WLED1 and WLED2 lines in TPS65217
+- isel: selection bit, valid values: 1 for ISEL1 (low-level) and 2 for ISEL2 (high-level)
+- fdim: PWM dimming frequency, valid values: 100, 200, 500, 1000
+- default-brightness: valid values: 0-100
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+       tps: tps@24 {
+               reg = <0x24>;
+               compatible = "ti,tps65217";
+               backlight {
+                       isel = <1>;  /* 1 - ISET1, 2 ISET2 */
+                       fdim = <100>; /* TPS65217_BL_FDIM_100HZ */
+                       default-brightness = <50>;
+               };
+       };
+
index d1a043339c11841109453170ae285d3ffa2954d9..9b40c4925aa9621e697b174e066db9d8699c1de7 100644 (file)
@@ -75,6 +75,14 @@ data that represent the following:
     Cell #3 (usr_id)  - mailbox user id for identifying the interrupt line
                         associated with generating a tx/rx fifo interrupt.
 
+Optional Properties:
+--------------------
+- ti,mbox-send-noirq:   Quirk flag to allow the client user of this sub-mailbox
+                        to send messages without triggering a Tx ready interrupt,
+                        and to control the Tx ticker. Should be used only on
+                        sub-mailboxes used to communicate with WkupM3 remote
+                        processor on AM33xx/AM43xx SoCs.
+
 Mailbox Users:
 ==============
 A device needing to communicate with a target processor device should specify
diff --git a/Documentation/devicetree/bindings/mailbox/sti-mailbox.txt b/Documentation/devicetree/bindings/mailbox/sti-mailbox.txt
new file mode 100644 (file)
index 0000000..b61eec9
--- /dev/null
@@ -0,0 +1,51 @@
+ST Microelectronics Mailbox Driver
+
+Each ST Mailbox IP currently consists of 4 instances of 32 channels.  Messages
+are passed between Application and Remote processors using shared memory.
+
+Controller
+----------
+
+Required properties:
+- compatible           : Should be "st,stih407-mailbox"
+- reg                  : Offset and length of the device's register set
+- mbox-name            : Name of the mailbox
+- #mbox-cells:         : Must be 2
+                         <&phandle instance channel direction>
+                           phandle   : Label name of controller
+                           instance  : Instance number
+                           channel   : Channel number
+
+Optional properties
+- interrupts           : Contains the IRQ line for a Rx mailbox
+
+Example:
+
+mailbox0: mailbox@0  {
+       compatible      = "st,stih407-mailbox";
+       reg             = <0x08f00000 0x1000>;
+       interrupts      = <GIC_SPI 1 IRQ_TYPE_NONE>;
+       #mbox-cells     = <2>;
+       mbox-name       = "a9";
+};
+
+Client
+------
+
+Required properties:
+- compatible           : Many (See the client docs)
+- reg                  : Shared (between Application and Remote) memory address
+- mboxes               : Standard property to specify a Mailbox (See ./mailbox.txt)
+                         Cells must match 'mbox-cells' (See Controller docs above)
+
+Optional properties
+- mbox-names           : Name given to channels seen in the 'mboxes' property.
+
+Example:
+
+mailbox_test {
+       compatible      = "mailbox_test";
+       reg             = <0x[shared_memory_address], [shared_memory_size]>;
+       mboxes          = <&mailbox2 0 1>, <&mailbox0 2 1>;
+       mbox-names      = "tx", "rx";
+};
diff --git a/Documentation/devicetree/bindings/memory-controllers/calxeda-ddr-ctrlr.txt b/Documentation/devicetree/bindings/memory-controllers/calxeda-ddr-ctrlr.txt
new file mode 100644 (file)
index 0000000..0496759
--- /dev/null
@@ -0,0 +1,16 @@
+Calxeda DDR memory controller
+
+Properties:
+- compatible : Should be:
+  - "calxeda,hb-ddr-ctrl" for ECX-1000
+  - "calxeda,ecx-2000-ddr-ctrl" for ECX-2000
+- reg : Address and size for DDR controller registers.
+- interrupts : Interrupt for DDR controller.
+
+Example:
+
+       memory-controller@fff00000 {
+               compatible = "calxeda,hb-ddr-ctrl";
+               reg = <0xfff00000 0x1000>;
+               interrupts = <0 91 4>;
+       };
diff --git a/Documentation/devicetree/bindings/metag/meta-intc.txt b/Documentation/devicetree/bindings/metag/meta-intc.txt
deleted file mode 100644 (file)
index 80994ad..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-* Meta External Trigger Controller Binding
-
-This binding specifies what properties must be available in the device tree
-representation of a Meta external trigger controller.
-
-Required properties:
-
-    - compatible: Specifies the compatibility list for the interrupt controller.
-      The type shall be <string> and the value shall include "img,meta-intc".
-
-    - num-banks: Specifies the number of interrupt banks (each of which can
-      handle 32 interrupt sources).
-
-    - interrupt-controller: The presence of this property identifies the node
-      as an interrupt controller. No property value shall be defined.
-
-    - #interrupt-cells: Specifies the number of cells needed to encode an
-      interrupt source. The type shall be a <u32> and the value shall be 2.
-
-    - #address-cells: Specifies the number of cells needed to encode an
-      address. The type shall be <u32> and the value shall be 0. As such,
-      'interrupt-map' nodes do not have to specify a parent unit address.
-
-Optional properties:
-
-    - no-mask: The controller doesn't have any mask registers.
-
-* Interrupt Specifier Definition
-
-  Interrupt specifiers consists of 2 cells encoded as follows:
-
-    - <1st-cell>: The interrupt-number that identifies the interrupt source.
-
-    - <2nd-cell>: The Linux interrupt flags containing level-sense information,
-                  encoded as follows:
-                    1 = edge triggered
-                    4 = level-sensitive
-
-* Examples
-
-Example 1:
-
-       /*
-        * Meta external trigger block
-        */
-       intc: intc {
-               // This is an interrupt controller node.
-               interrupt-controller;
-
-               // No address cells so that 'interrupt-map' nodes which
-               // reference this interrupt controller node do not need a parent
-               // address specifier.
-               #address-cells = <0>;
-
-               // Two cells to encode interrupt sources.
-               #interrupt-cells = <2>;
-
-               // Number of interrupt banks
-               num-banks = <2>;
-
-               // No HWMASKEXT is available (specify on Chorus2 and Comet ES1)
-               no-mask;
-
-               // Compatible with Meta hardware trigger block.
-               compatible = "img,meta-intc";
-       };
-
-Example 2:
-
-       /*
-        * An interrupt generating device that is wired to a Meta external
-        * trigger block.
-        */
-       uart1: uart@0x02004c00 {
-               // Interrupt source '5' that is level-sensitive.
-               // Note that there are only two cells as specified in the
-               // interrupt parent's '#interrupt-cells' property.
-               interrupts = <5 4 /* level */>;
-
-               // The interrupt controller that this device is wired to.
-               interrupt-parent = <&intc>;
-       };
diff --git a/Documentation/devicetree/bindings/metag/pdc-intc.txt b/Documentation/devicetree/bindings/metag/pdc-intc.txt
deleted file mode 100644 (file)
index a691185..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-* ImgTec Powerdown Controller (PDC) Interrupt Controller Binding
-
-This binding specifies what properties must be available in the device tree
-representation of a PDC IRQ controller. This has a number of input interrupt
-lines which can wake the system, and are passed on through output interrupt
-lines.
-
-Required properties:
-
-    - compatible: Specifies the compatibility list for the interrupt controller.
-      The type shall be <string> and the value shall include "img,pdc-intc".
-
-    - reg: Specifies the base PDC physical address(s) and size(s) of the
-      addressable register space. The type shall be <prop-encoded-array>.
-
-    - interrupt-controller: The presence of this property identifies the node
-      as an interrupt controller. No property value shall be defined.
-
-    - #interrupt-cells: Specifies the number of cells needed to encode an
-      interrupt source. The type shall be a <u32> and the value shall be 2.
-
-    - num-perips: Number of waking peripherals.
-
-    - num-syswakes: Number of SysWake inputs.
-
-    - interrupts: List of interrupt specifiers. The first specifier shall be the
-      shared SysWake interrupt, and remaining specifies shall be PDC peripheral
-      interrupts in order.
-
-* Interrupt Specifier Definition
-
-  Interrupt specifiers consists of 2 cells encoded as follows:
-
-    - <1st-cell>: The interrupt-number that identifies the interrupt source.
-                    0-7:  Peripheral interrupts
-                    8-15: SysWake interrupts
-
-    - <2nd-cell>: The level-sense information, encoded using the Linux interrupt
-                  flags as follows (only 4 valid for peripheral interrupts):
-                    0 = none (decided by software)
-                    1 = low-to-high edge triggered
-                    2 = high-to-low edge triggered
-                    3 = both edge triggered
-                    4 = active-high level-sensitive (required for perip irqs)
-                    8 = active-low level-sensitive
-
-* Examples
-
-Example 1:
-
-       /*
-        * TZ1090 PDC block
-        */
-       pdc: pdc@0x02006000 {
-               // This is an interrupt controller node.
-               interrupt-controller;
-
-               // Three cells to encode interrupt sources.
-               #interrupt-cells = <2>;
-
-               // Offset address of 0x02006000 and size of 0x1000.
-               reg = <0x02006000 0x1000>;
-
-               // Compatible with Meta hardware trigger block.
-               compatible = "img,pdc-intc";
-
-               // Three peripherals are connected.
-               num-perips = <3>;
-
-               // Four SysWakes are connected.
-               num-syswakes = <4>;
-
-               interrupts = <18 4 /* level */>, /* Syswakes */
-                            <30 4 /* level */>, /* Peripheral 0 (RTC) */
-                            <29 4 /* level */>, /* Peripheral 1 (IR) */
-                            <31 4 /* level */>; /* Peripheral 2 (WDT) */
-       };
-
-Example 2:
-
-       /*
-        * An SoC peripheral that is wired through the PDC.
-        */
-       rtc0 {
-               // The interrupt controller that this device is wired to.
-               interrupt-parent = <&pdc>;
-
-               // Interrupt source Peripheral 0
-               interrupts = <0   /* Peripheral 0 (RTC) */
-                             4>  /* IRQ_TYPE_LEVEL_HIGH */
-       };
-
-Example 3:
-
-       /*
-        * An interrupt generating device that is wired to a SysWake pin.
-        */
-       touchscreen0 {
-               // The interrupt controller that this device is wired to.
-               interrupt-parent = <&pdc>;
-
-               // Interrupt source SysWake 0 that is active-low level-sensitive
-               interrupts = <8 /* SysWake0 */
-                             8 /* IRQ_TYPE_LEVEL_LOW */>;
-       };
index ad5d90482a0e07d9ae7dd3efde4fa7eef13abcd8..670831b29565369279960e9eddb2e14b4267ccdd 100644 (file)
@@ -15,7 +15,7 @@ Required properties:
 
 The HLCDC IP exposes two subdevices:
  - a PWM chip: see ../pwm/atmel-hlcdc-pwm.txt
- - a Display Controller: see ../drm/atmel-hlcdc-dc.txt
+ - a Display Controller: see ../display/atmel-hlcdc-dc.txt
 
 Example:
 
index 35181794aa241b7f147dd8e0afdffa9db216e602..511764acd4d5f418664c014156788ebf8da06ec6 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
 
 Required child nodes:
 - backlight    : container node for backlight following the binding
-               in video/backlight/sky81452-backlight.txt
+               in leds/backlight/sky81452-backlight.txt
 - regulator    : container node for regulators following the binding
                in regulator/sky81452-regulator.txt
 
index 37bf7f1aa70a23a310c6a00f4f5e864f48b7ebff..23fc2f21f5a467bdf5ae4bb42655d0e7c2bda5f8 100644 (file)
@@ -56,6 +56,7 @@ Optional nodes:
    bindings/input/matrix-keymap.txt
  - linux,no-autorepeat: do no enable autorepeat feature.
  - wakeup-source: use any event on keypad as wakeup event.
+                 (Legacy property supported: "linux,wakeup")
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
deleted file mode 100644 (file)
index 973c272..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-MIPI DSI (Display Serial Interface) busses
-==========================================
-
-The MIPI Display Serial Interface specifies a serial bus and a protocol for
-communication between a host and up to four peripherals. This document will
-define the syntax used to represent a DSI bus in a device tree.
-
-This document describes DSI bus-specific properties only or defines existing
-standard properties in the context of the DSI bus.
-
-Each DSI host provides a DSI bus. The DSI host controller's node contains a
-set of properties that characterize the bus. Child nodes describe individual
-peripherals on that bus.
-
-The following assumes that only a single peripheral is connected to a DSI
-host. Experience shows that this is true for the large majority of setups.
-
-DSI host
---------
-
-In addition to the standard properties and those defined by the parent bus of
-a DSI host, the following properties apply to a node representing a DSI host.
-
-Required properties:
-- #address-cells: The number of cells required to represent an address on the
-  bus. DSI peripherals are addressed using a 2-bit virtual channel number, so
-  a maximum of 4 devices can be addressed on a single bus. Hence the value of
-  this property should be 1.
-- #size-cells: Should be 0. There are cases where it makes sense to use a
-  different value here. See below.
-
-DSI peripheral
---------------
-
-Peripherals are represented as child nodes of the DSI host's node. Properties
-described here apply to all DSI peripherals, but individual bindings may want
-to define additional, device-specific properties.
-
-Required properties:
-- reg: The virtual channel number of a DSI peripheral. Must be in the range
-  from 0 to 3.
-
-Some DSI peripherals respond to more than a single virtual channel. In that
-case two alternative representations can be chosen:
-- The reg property can take multiple entries, one for each virtual channel
-  that the peripheral responds to.
-- If the virtual channels that a peripheral responds to are consecutive, the
-  #size-cells can be set to 1. The first cell of each entry in the reg
-  property is the number of the first virtual channel and the second cell is
-  the number of consecutive virtual channels.
-
-Example
--------
-
-       dsi-host {
-               ...
-
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               /* peripheral responds to virtual channel 0 */
-               peripheral@0 {
-                       compatible = "...";
-                       reg = <0>;
-               };
-
-               ...
-       };
-
-       dsi-host {
-               ...
-
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               /* peripheral responds to virtual channels 0 and 2 */
-               peripheral@0 {
-                       compatible = "...";
-                       reg = <0, 2>;
-               };
-
-               ...
-       };
-
-       dsi-host {
-               ...
-
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               /* peripheral responds to virtual channels 1, 2 and 3 */
-               peripheral@1 {
-                       compatible = "...";
-                       reg = <1 3>;
-               };
-
-               ...
-       };
diff --git a/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt
deleted file mode 100644 (file)
index e4a25ce..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-NVIDIA Tegra MIPI pad calibration controller
-
-Required properties:
-- compatible: "nvidia,tegra<chip>-mipi"
-- reg: Physical base address and length of the controller's registers.
-- clocks: Must contain an entry for each entry in clock-names.
-  See ../clocks/clock-bindings.txt for details.
-- clock-names: Must include the following entries:
-  - mipi-cal
-- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads
-  that need to be calibrated for a given device.
-
-User nodes need to contain an nvidia,mipi-calibrate property that has a
-phandle to refer to the calibration controller node and a bitmask of the pads
-that need to be calibrated.
-
-Example:
-
-       mipi: mipi@700e3000 {
-               compatible = "nvidia,tegra114-mipi";
-               reg = <0x700e3000 0x100>;
-               clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>;
-               clock-names = "mipi-cal";
-               #nvidia,mipi-calibrate-cells = <1>;
-       };
-
-       ...
-
-       host1x@50000000 {
-               ...
-
-               dsi@54300000 {
-                       ...
-
-                       nvidia,mipi-calibrate = <&mipi 0x060>;
-
-                       ...
-               };
-
-               ...
-       };
diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt
deleted file mode 100644 (file)
index 1d34471..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-EEPROMs (SPI) compatible with Atmel at25.
-
-Required properties:
-- compatible : "atmel,at25".
-- reg : chip select number
-- spi-max-frequency : max spi frequency to use
-- pagesize : size of the eeprom page
-- size : total eeprom size in bytes
-- address-width : number of address bits (one of 8, 16, or 24)
-
-Optional properties:
-- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
-- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
-- read-only : this parameter-less property disables writes to the eeprom
-
-Obsolete legacy properties are can be used in place of "size", "pagesize",
-"address-width", and "read-only":
-- at25,byte-len : total eeprom size in bytes
-- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
-- at25,page-size : size of the eeprom page
-
-Additional compatible properties are also allowed.
-
-Example:
-       at25@0 {
-               compatible = "atmel,at25", "st,m95256";
-               reg = <0>
-               spi-max-frequency = <5000000>;
-               spi-cpha;
-               spi-cpol;
-
-               pagesize = <64>;
-               size = <32768>;
-               address-width = <16>;
-       };
diff --git a/Documentation/devicetree/bindings/misc/bmp085.txt b/Documentation/devicetree/bindings/misc/bmp085.txt
deleted file mode 100644 (file)
index d7a6deb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-BMP085/BMP18x digital pressure sensors
-
-Required properties:
-- compatible: bosch,bmp085
-
-Optional properties:
-- chip-id: configurable chip id for non-default chip revisions
-- temp-measurement-period: temperature measurement period (milliseconds)
-- default-oversampling: default oversampling value to be used at startup,
-  value range is 0-3 with rising sensitivity.
-- interrupt-parent: should be the phandle for the interrupt controller
-- interrupts: interrupt mapping for IRQ
-
-Example:
-
-pressure@77 {
-       compatible = "bosch,bmp085";
-       reg = <0x77>;
-       chip-id = <10>;
-       temp-measurement-period = <100>;
-       default-oversampling = <2>;
-       interrupt-parent = <&gpio0>;
-       interrupts = <25 IRQ_TYPE_EDGE_RISING>;
-};
diff --git a/Documentation/devicetree/bindings/misc/lis302.txt b/Documentation/devicetree/bindings/misc/lis302.txt
deleted file mode 100644 (file)
index 2a19bff..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-LIS302 accelerometer devicetree bindings
-
-This device is matched via its bus drivers, and has a number of properties
-that apply in on the generic device (independent from the bus).
-
-
-Required properties for the SPI bindings:
- - compatible:                 should be set to "st,lis3lv02d_spi"
- - reg:                        the chipselect index
- - spi-max-frequency:  maximal bus speed, should be set to 1000000 unless
-                       constrained by external circuitry
- - interrupts:         the interrupt generated by the device
-
-Required properties for the I2C bindings:
- - compatible:         should be set to "st,lis3lv02d"
- - reg:                        i2c slave address
- - Vdd-supply:         The input supply for Vdd
- - Vdd_IO-supply:      The input supply for Vdd_IO
-
-
-Optional properties for all bus drivers:
-
- - st,click-single-{x,y,z}:    if present, tells the device to issue an
-                               interrupt on single click events on the
-                               x/y/z axis.
- - st,click-double-{x,y,z}:    if present, tells the device to issue an
-                               interrupt on double click events on the
-                               x/y/z axis.
- - st,click-thresh-{x,y,z}:    set the x/y/z axis threshold
- - st,click-click-time-limit:  click time limit, from 0 to 127.5msec
-                               with step of 0.5 msec
- - st,click-latency:           click latency, from 0 to 255 msec with
-                               step of 1 msec.
- - st,click-window:            click window, from 0 to 255 msec with
-                               step of 1 msec.
- - st,irq{1,2}-disable:                disable IRQ 1/2
- - st,irq{1,2}-ff-wu-1:                raise IRQ 1/2 on FF_WU_1 condition
- - st,irq{1,2}-ff-wu-2:                raise IRQ 1/2 on FF_WU_2 condition
- - st,irq{1,2}-data-ready:     raise IRQ 1/2 on data ready contition
- - st,irq{1,2}-click:          raise IRQ 1/2 on click condition
- - st,irq-open-drain:          consider IRQ lines open-drain
- - st,irq-active-low:          make IRQ lines active low
- - st,wu-duration-1:           duration register for Free-Fall/Wake-Up
-                               interrupt 1
- - st,wu-duration-2:           duration register for Free-Fall/Wake-Up
-                               interrupt 2
- - st,wakeup-{x,y,z}-{lo,hi}:  set wakeup condition on x/y/z axis for
-                               upper/lower limit
- - st,wakeup-threshold:                set wakeup threshold
- - st,wakeup2-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for
-                               upper/lower limit for second wakeup
-                               engine.
- - st,wakeup2-threshold:       set wakeup threshold for second wakeup
-                               engine.
- - st,highpass-cutoff-hz=:     1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
-                               highpass cut-off frequency
- - st,hipass{1,2}-disable:     disable highpass 1/2.
- - st,default-rate=:           set the default rate
- - st,axis-{x,y,z}=:           set the axis to map to the three coordinates.
-                               Negative values can be used for inverted axis.
- - st,{min,max}-limit-{x,y,z}  set the min/max limits for x/y/z axis
-                               (used by self-test)
-
-
-Example for a SPI device node:
-
-       lis302@0 {
-               compatible = "st,lis302dl-spi";
-               reg = <0>;
-               spi-max-frequency = <1000000>;
-               interrupt-parent = <&gpio>;
-               interrupts = <104 0>;
-
-               st,click-single-x;
-               st,click-single-y;
-               st,click-single-z;
-               st,click-thresh-x = <10>;
-               st,click-thresh-y = <10>;
-               st,click-thresh-z = <10>;
-               st,irq1-click;
-               st,irq2-click;
-               st,wakeup-x-lo;
-               st,wakeup-x-hi;
-               st,wakeup-y-lo;
-               st,wakeup-y-hi;
-               st,wakeup-z-lo;
-               st,wakeup-z-hi;
-       };
-
-Example for a I2C device node:
-
-       lis331dlh: lis331dlh@18 {
-               compatible = "st,lis331dlh", "st,lis3lv02d";
-               reg = <0x18>;
-               Vdd-supply = <&lis3_reg>;
-               Vdd_IO-supply = <&lis3_reg>;
-
-               st,click-single-x;
-               st,click-single-y;
-               st,click-single-z;
-               st,click-thresh-x = <10>;
-               st,click-thresh-y = <10>;
-               st,click-thresh-z = <10>;
-               st,irq1-click;
-               st,irq2-click;
-               st,wakeup-x-lo;
-               st,wakeup-x-hi;
-               st,wakeup-y-lo;
-               st,wakeup-y-hi;
-               st,wakeup-z-lo;
-               st,wakeup-z-hi;
-               st,min-limit-x = <120>;
-               st,min-limit-y = <120>;
-               st,min-limit-z = <140>;
-               st,max-limit-x = <550>;
-               st,max-limit-y = <550>;
-               st,max-limit-z = <750>;
-       };
-
diff --git a/Documentation/devicetree/bindings/misc/ti,dac7512.txt b/Documentation/devicetree/bindings/misc/ti,dac7512.txt
deleted file mode 100644 (file)
index 1db4593..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-TI DAC7512 DEVICETREE BINDINGS
-
-Required properties:
-
-       - "compatible"          Must be set to "ti,dac7512"
-
-Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
-apply. In particular, "reg" and "spi-max-frequency" properties must be given.
-
-
-Example:
-
-       spi_master {
-               dac7512: dac7512@0 {
-                       compatible = "ti,dac7512";
-                       reg = <0>; /* CS0 */
-                       spi-max-frequency = <1000000>;
-               };
-       };
-
index f693baf87264d6525b105c0eb244730111b47820..ed23b9bedfdc05425fe7f01486a4f5ed7c7f8e95 100644 (file)
@@ -68,7 +68,8 @@ polarity is in effect.
 
 Optional SDIO properties:
 - keep-power-in-suspend: Preserves card power during a suspend/resume cycle
-- enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion
+- wakeup-source: Enables wake up of host system on SDIO IRQ assertion
+                (Legacy property supported: "enable-sdio-wakeup")
 
 
 MMC power sequences:
@@ -118,7 +119,7 @@ sdhci@ab000000 {
        wp-gpios = <&gpio 70 0>;
        max-frequency = <50000000>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        mmc-pwrseq = <&sdhci0_pwrseq>
 }
 
index 5235cbc551b014eef7f1f0936f46298bae9ee3b4..32636eb77304ce497f55b743d4f37c6ed2fed780 100644 (file)
@@ -30,6 +30,12 @@ Optional properties:
                  command is asserted. Zero means one cycle, 255 means 256
                  cycles.
 - bank: default NAND bank to use (0-3 are valid, 0 is the default).
+- nand-ecc-mode      : see nand.txt
+- nand-ecc-strength  : see nand.txt
+- nand-ecc-step-size : see nand.txt
+
+Can support 1-bit HW ECC (default) or if stronger correction is required,
+software-based BCH.
 
 Example:
 
index 8e5557da1955472b3b2faf8b6c638e9ef5e61293..f1e2a02381a498a8f94e379870a8dcb1d2dec4ca 100644 (file)
@@ -4,10 +4,17 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
-NOTE: if the sub-node has a compatible string, then it is not a partition.
 
-#address-cells & #size-cells must both be present in the mtd device. There are
-two valid values for both:
+The partition table should be a subnode of the mtd node and should be named
+'partitions'. Partitions are defined in subnodes of the partitions node.
+
+For backwards compatibility partitions as direct subnodes of the mtd device are
+supported. This use is discouraged.
+NOTE: also for backwards compatibility, direct subnodes that have a compatible
+string are not considered partitions, as they may be used for other bindings.
+
+#address-cells & #size-cells must both be present in the partitions subnode of the
+mtd device. There are two valid values for both:
 <1>: for partitions that require a single 32-bit cell to represent their
      size/address (aka the value is below 4 GiB)
 <2>: for partitions that require two 32-bit cells to represent their
@@ -28,44 +35,50 @@ Examples:
 
 
 flash@0 {
-       #address-cells = <1>;
-       #size-cells = <1>;
+       partitions {
+               #address-cells = <1>;
+               #size-cells = <1>;
 
-       partition@0 {
-               label = "u-boot";
-               reg = <0x0000000 0x100000>;
-               read-only;
-       };
+               partition@0 {
+                       label = "u-boot";
+                       reg = <0x0000000 0x100000>;
+                       read-only;
+               };
 
-       uimage@100000 {
-               reg = <0x0100000 0x200000>;
+               uimage@100000 {
+                       reg = <0x0100000 0x200000>;
+               };
        };
 };
 
 flash@1 {
-       #address-cells = <1>;
-       #size-cells = <2>;
+       partitions {
+               #address-cells = <1>;
+               #size-cells = <2>;
 
-       /* a 4 GiB partition */
-       partition@0 {
-               label = "filesystem";
-               reg = <0x00000000 0x1 0x00000000>;
+               /* a 4 GiB partition */
+               partition@0 {
+                       label = "filesystem";
+                       reg = <0x00000000 0x1 0x00000000>;
+               };
        };
 };
 
 flash@2 {
-       #address-cells = <2>;
-       #size-cells = <2>;
+       partitions {
+               #address-cells = <2>;
+               #size-cells = <2>;
 
-       /* an 8 GiB partition */
-       partition@0 {
-               label = "filesystem #1";
-               reg = <0x0 0x00000000 0x2 0x00000000>;
-       };
+               /* an 8 GiB partition */
+               partition@0 {
+                       label = "filesystem #1";
+                       reg = <0x0 0x00000000 0x2 0x00000000>;
+               };
 
-       /* a 4 GiB partition */
-       partition@200000000 {
-               label = "filesystem #2";
-               reg = <0x2 0x00000000 0x1 0x00000000>;
+               /* a 4 GiB partition */
+               partition@200000000 {
+                       label = "filesystem #2";
+                       reg = <0x2 0x00000000 0x1 0x00000000>;
+               };
        };
 };
diff --git a/Documentation/devicetree/bindings/mtd/vf610-nfc.txt b/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
new file mode 100644 (file)
index 0000000..c96eeb6
--- /dev/null
@@ -0,0 +1,59 @@
+Freescale's NAND flash controller (NFC)
+
+This variant of the Freescale NAND flash controller (NFC) can be found on
+Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70.
+
+Required properties:
+- compatible: Should be set to "fsl,vf610-nfc".
+- reg: address range of the NFC.
+- interrupts: interrupt of the NFC.
+- #address-cells: shall be set to 1. Encode the nand CS.
+- #size-cells : shall be set to 0.
+- assigned-clocks: main clock from the SoC, for Vybrid <&clks VF610_CLK_NFC>;
+- assigned-clock-rates: The NAND bus timing is derived from this clock
+    rate and should not exceed maximum timing for any NAND memory chip
+    in a board stuffing. Typical NAND memory timings derived from this
+    clock are found in the SoC hardware reference manual. Furthermore,
+    there might be restrictions on maximum rates when using hardware ECC.
+
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+
+Required children nodes:
+Children nodes represent the available nand chips. Currently the driver can
+only handle one NAND chip.
+
+Required properties:
+- compatible: Should be set to "fsl,vf610-nfc-cs".
+- nand-bus-width: see nand.txt
+- nand-ecc-mode: see nand.txt
+
+Required properties for hardware ECC:
+- nand-ecc-strength: supported strengths are 24 and 32 bit (see nand.txt)
+- nand-ecc-step-size: step size equals page size, currently only 2k pages are
+    supported
+- nand-on-flash-bbt: see nand.txt
+
+Example:
+
+       nfc: nand@400e0000 {
+               compatible = "fsl,vf610-nfc";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x400e0000 0x4000>;
+               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clks VF610_CLK_NFC>;
+               clock-names = "nfc";
+               assigned-clocks = <&clks VF610_CLK_NFC>;
+               assigned-clock-rates = <33000000>;
+
+               nand@0 {
+                       compatible = "fsl,vf610-nfc-nandcs";
+                       reg = <0>;
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "hw";
+                       nand-ecc-strength = <32>;
+                       nand-ecc-step-size = <2048>;
+                       nand-on-flash-bbt;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt
deleted file mode 100644 (file)
index 5ae601e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-NVIDIA compliant embedded controller
-
-Required properties:
-- compatible : should be "nvidia,nvec".
-- reg : the iomem of the i2c slave controller
-- interrupts : the interrupt line of the i2c slave controller
-- clock-frequency : the frequency of the i2c bus
-- gpios : the gpio used for ec request
-- slave-addr: the i2c address of the slave controller
-- clocks : Must contain an entry for each entry in clock-names.
-  See ../clocks/clock-bindings.txt for details.
-- clock-names : Must include the following entries:
-  Tegra20/Tegra30:
-  - div-clk
-  - fast-clk
-  Tegra114:
-  - div-clk
-- resets : Must contain an entry for each entry in reset-names.
-  See ../reset/reset.txt for details.
-- reset-names : Must include the following entries:
-  - i2c
diff --git a/Documentation/devicetree/bindings/open-pic.txt b/Documentation/devicetree/bindings/open-pic.txt
deleted file mode 100644 (file)
index 909a902..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-* Open PIC Binding
-
-This binding specifies what properties must be available in the device tree
-representation of an Open PIC compliant interrupt controller.  This binding is
-based on the binding defined for Open PIC in [1] and is a superset of that
-binding.
-
-Required properties:
-
-  NOTE: Many of these descriptions were paraphrased here from [1] to aid
-        readability.
-
-    - compatible: Specifies the compatibility list for the PIC.  The type
-      shall be <string> and the value shall include "open-pic".
-
-    - reg: Specifies the base physical address(s) and size(s) of this
-      PIC's addressable register space.  The type shall be <prop-encoded-array>.
-
-    - interrupt-controller: The presence of this property identifies the node
-      as an Open PIC.  No property value shall be defined.
-
-    - #interrupt-cells: Specifies the number of cells needed to encode an
-      interrupt source.  The type shall be a <u32> and the value shall be 2.
-
-    - #address-cells: Specifies the number of cells needed to encode an
-      address.  The type shall be <u32> and the value shall be 0.  As such,
-      'interrupt-map' nodes do not have to specify a parent unit address.
-
-Optional properties:
-
-    - pic-no-reset: The presence of this property indicates that the PIC
-      shall not be reset during runtime initialization.  No property value shall
-      be defined.  The presence of this property also mandates that any
-      initialization related to interrupt sources shall be limited to sources
-      explicitly referenced in the device tree.
-
-* Interrupt Specifier Definition
-
-  Interrupt specifiers consists of 2 cells encoded as
-  follows:
-
-    - <1st-cell>: The interrupt-number that identifies the interrupt source.
-
-    - <2nd-cell>: The level-sense information, encoded as follows:
-                    0 = low-to-high edge triggered
-                    1 = active low level-sensitive
-                    2 = active high level-sensitive
-                    3 = high-to-low edge triggered
-
-* Examples
-
-Example 1:
-
-       /*
-        * An Open PIC interrupt controller
-        */
-       mpic: pic@40000 {
-               // This is an interrupt controller node.
-               interrupt-controller;
-
-               // No address cells so that 'interrupt-map' nodes which reference
-               // this Open PIC node do not need a parent address specifier.
-               #address-cells = <0>;
-
-               // Two cells to encode interrupt sources.
-               #interrupt-cells = <2>;
-
-               // Offset address of 0x40000 and size of 0x40000.
-               reg = <0x40000 0x40000>;
-
-               // Compatible with Open PIC.
-               compatible = "open-pic";
-
-               // The PIC shall not be reset.
-               pic-no-reset;
-       };
-
-Example 2:
-
-       /*
-        * An interrupt generating device that is wired to an Open PIC.
-        */
-       serial0: serial@4500 {
-               // Interrupt source '42' that is active high level-sensitive.
-               // Note that there are only two cells as specified in the interrupt
-               // parent's '#interrupt-cells' property.
-               interrupts = <42 2>;
-
-               // The interrupt controller that this device is wired to.
-               interrupt-parent = <&mpic>;
-       };
-
-* References
-
-[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform
-    Requirements (ePAPR), Version 1.0, July 2008.
-    (http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf)
-
diff --git a/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt b/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt
deleted file mode 100644 (file)
index 83e2cae..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "ampire,am800480r3tmqwa1h"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b080uan01.txt b/Documentation/devicetree/bindings/panel/auo,b080uan01.txt
deleted file mode 100644 (file)
index bae0e2b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 8.0" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101ean01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt
deleted file mode 100644 (file)
index 72e088a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101aw03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b101ean01.txt b/Documentation/devicetree/bindings/panel/auo,b101ean01.txt
deleted file mode 100644 (file)
index 3590b07..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101ean01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b101xtn01.txt b/Documentation/devicetree/bindings/panel/auo,b101xtn01.txt
deleted file mode 100644 (file)
index 889d511..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101xtn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b116xw03.txt b/Documentation/devicetree/bindings/panel/auo,b116xw03.txt
deleted file mode 100644 (file)
index 690d0a5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
-
-Required properties:
-- compatible: should be "auo,b116xw03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b133htn01.txt b/Documentation/devicetree/bindings/panel/auo,b133htn01.txt
deleted file mode 100644 (file)
index 302226b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
-
-Required properties:
-- compatible: should be "auo,b133htn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/auo,b133xtn01.txt b/Documentation/devicetree/bindings/panel/auo,b133xtn01.txt
deleted file mode 100644 (file)
index 7443b7c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b133xtn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt b/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt
deleted file mode 100644 (file)
index b6f2f3e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
-
-Required properties:
-- compatible: should be "avic,tm070ddh03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt
deleted file mode 100644 (file)
index f24614e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "chunghwa,claa101wa01a"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt
deleted file mode 100644 (file)
index 0ab2c05..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "chunghwa,claa101wb03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/edt,et057090dhu.txt b/Documentation/devicetree/bindings/panel/edt,et057090dhu.txt
deleted file mode 100644 (file)
index 4903d7b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Emerging Display Technology Corp. 5.7" VGA TFT LCD panel
-
-Required properties:
-- compatible: should be "edt,et057090dhu"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/edt,et070080dh6.txt b/Documentation/devicetree/bindings/panel/edt,et070080dh6.txt
deleted file mode 100644 (file)
index 20cb38e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-Emerging Display Technology Corp. ET070080DH6 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "edt,et070080dh6"
-
-This panel is the same as ETM0700G0DH6 except for the touchscreen.
-ET070080DH6 is the model with resistive touch.
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/edt,etm0700g0dh6.txt b/Documentation/devicetree/bindings/panel/edt,etm0700g0dh6.txt
deleted file mode 100644 (file)
index ee4b180..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-Emerging Display Technology Corp. ETM0700G0DH6 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "edt,etm0700g0dh6"
-
-This panel is the same as ET070080DH6 except for the touchscreen.
-ETM0700G0DH6 is the model with capacitive multitouch.
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt b/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt
deleted file mode 100644 (file)
index b47f9d8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Foxlink Group 5" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "foxlink,fl500wvr00-a0t"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt b/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt
deleted file mode 100644 (file)
index 24b0b62..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "giantplus,gpg48273qs5"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt b/Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt
deleted file mode 100644 (file)
index 7da1d5c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "hannstar,hsd070pww1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt b/Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt
deleted file mode 100644 (file)
index 8270319..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
-
-Required properties:
-- compatible: should be "hannstar,hsd100pxn1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt b/Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt
deleted file mode 100644 (file)
index 04caaae..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
-
-Required properties:
-- compatible: should be "hit,tx23d38vm0caa"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,at043tn24.txt b/Documentation/devicetree/bindings/panel/innolux,at043tn24.txt
deleted file mode 100644 (file)
index 4104226..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux AT043TN24 4.3" WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,at043tn24"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt b/Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt
deleted file mode 100644 (file)
index 2743b07..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,g121i1-l01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,n116bge.txt b/Documentation/devicetree/bindings/panel/innolux,n116bge.txt
deleted file mode 100644 (file)
index 081bb93..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,n116bge"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt b/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt
deleted file mode 100644 (file)
index 7825844..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-InnoLux 15.6" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,n156bge-l21"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt b/Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt
deleted file mode 100644 (file)
index 824f87f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,zj070na-01p"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lb070wv8.txt b/Documentation/devicetree/bindings/panel/lg,lb070wv8.txt
deleted file mode 100644 (file)
index a7588e5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 7" (800x480 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lb070wv8"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt b/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt
deleted file mode 100644 (file)
index 5e649cb..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG Corporation 7" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,ld070wx3-sl01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lg4573.txt b/Documentation/devicetree/bindings/panel/lg,lg4573.txt
deleted file mode 100644 (file)
index 824441f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-LG LG4573 TFT Liquid Crystal Display with SPI control bus
-
-Required properties:
-  - compatible: "lg,lg4573"
-  - reg: address of the panel on the SPI bus
-
-The panel must obey rules for SPI slave device specified in document [1].
-
-[1]: Documentation/devicetree/bindings/spi/spi-bus.txt
-
-Example:
-
-       lcd_panel: display@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "lg,lg4573";
-               spi-max-frequency = <10000000>;
-               reg = <0>;
-       };
diff --git a/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt b/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt
deleted file mode 100644 (file)
index a04fd2b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG Corporation 5" HD TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lh500wx1-sd03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lp129qe.txt b/Documentation/devicetree/bindings/panel/lg,lp129qe.txt
deleted file mode 100644 (file)
index 9f262e0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 12.9" (2560x1700 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lp129qe"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt b/Documentation/devicetree/bindings/panel/nec,nl4827hc19-05b.txt
deleted file mode 100644 (file)
index 8e1914d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "nec,nl4827hc19-05b"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/okaya,rs800480t-7x0gp.txt b/Documentation/devicetree/bindings/panel/okaya,rs800480t-7x0gp.txt
deleted file mode 100644 (file)
index ddf8e21..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel
-
-Required properties:
-- compatible: should be "okaya,rs800480t-7x0gp"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt b/Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt
deleted file mode 100644 (file)
index de19e93..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
-
-Required properties:
-- compatible: should be "ortustech,com43h4m85ulc"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt
deleted file mode 100644 (file)
index d328b03..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Panasonic Corporation 10.1" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "panasonic,vvx10f004b00"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/samsung,ld9040.txt b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt
deleted file mode 100644 (file)
index 07c36c3..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus
-
-Required properties:
-  - compatible: "samsung,ld9040"
-  - reg: address of the panel on SPI bus
-  - vdd3-supply: core voltage supply
-  - vci-supply: voltage supply for analog circuits
-  - reset-gpios: a GPIO spec for the reset pin
-  - display-timings: timings for the connected panel according to [1]
-
-The panel must obey rules for SPI slave device specified in document [2].
-
-Optional properties:
-  - power-on-delay: delay after turning regulators on [ms]
-  - reset-delay: delay after reset sequence [ms]
-  - panel-width-mm: physical panel width [mm]
-  - panel-height-mm: physical panel height [mm]
-
-The device node can contain one 'port' child node with one child
-'endpoint' node, according to the bindings defined in [3]. This
-node should describe panel's video bus.
-
-[1]: Documentation/devicetree/bindings/video/display-timing.txt
-[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
-[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-       lcd@0 {
-               compatible = "samsung,ld9040";
-               reg = <0>;
-               vdd3-supply = <&ldo7_reg>;
-               vci-supply = <&ldo17_reg>;
-               reset-gpios = <&gpy4 5 0>;
-               spi-max-frequency = <1200000>;
-               spi-cpol;
-               spi-cpha;
-               power-on-delay = <10>;
-               reset-delay = <10>;
-               panel-width-mm = <90>;
-               panel-height-mm = <154>;
-
-               display-timings {
-                       timing {
-                               clock-frequency = <23492370>;
-                               hactive = <480>;
-                               vactive = <800>;
-                               hback-porch = <16>;
-                               hfront-porch = <16>;
-                               vback-porch = <2>;
-                               vfront-porch = <28>;
-                               hsync-len = <2>;
-                               vsync-len = <1>;
-                               hsync-active = <0>;
-                               vsync-active = <0>;
-                               de-active = <0>;
-                               pixelclk-active = <0>;
-                       };
-               };
-
-               port {
-                       lcd_ep: endpoint {
-                               remote-endpoint = <&fimd_dpi_ep>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt b/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt
deleted file mode 100644 (file)
index ef522c6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Samsung Electronics 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "samsung,ltn101nt05"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt b/Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt
deleted file mode 100644 (file)
index e7f969d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "samsung,ltn140at29-301"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt
deleted file mode 100644 (file)
index e7ee988..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-Samsung S6E8AA0 AMOLED LCD 5.3 inch panel
-
-Required properties:
-  - compatible: "samsung,s6e8aa0"
-  - reg: the virtual channel number of a DSI peripheral
-  - vdd3-supply: core voltage supply
-  - vci-supply: voltage supply for analog circuits
-  - reset-gpios: a GPIO spec for the reset pin
-  - display-timings: timings for the connected panel as described by [1]
-
-Optional properties:
-  - power-on-delay: delay after turning regulators on [ms]
-  - reset-delay: delay after reset sequence [ms]
-  - init-delay: delay after initialization sequence [ms]
-  - panel-width-mm: physical panel width [mm]
-  - panel-height-mm: physical panel height [mm]
-  - flip-horizontal: boolean to flip image horizontally
-  - flip-vertical: boolean to flip image vertically
-
-The device node can contain one 'port' child node with one child
-'endpoint' node, according to the bindings defined in [2]. This
-node should describe panel's video bus.
-
-[1]: Documentation/devicetree/bindings/video/display-timing.txt
-[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-       panel {
-               compatible = "samsung,s6e8aa0";
-               reg = <0>;
-               vdd3-supply = <&vcclcd_reg>;
-               vci-supply = <&vlcd_reg>;
-               reset-gpios = <&gpy4 5 0>;
-               power-on-delay= <50>;
-               reset-delay = <100>;
-               init-delay = <100>;
-               panel-width-mm = <58>;
-               panel-height-mm = <103>;
-               flip-horizontal;
-               flip-vertical;
-
-               display-timings {
-                       timing0: timing-0 {
-                               clock-frequency = <57153600>;
-                               hactive = <720>;
-                               vactive = <1280>;
-                               hfront-porch = <5>;
-                               hback-porch = <5>;
-                               hsync-len = <5>;
-                               vfront-porch = <13>;
-                               vback-porch = <1>;
-                               vsync-len = <2>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt b/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt
deleted file mode 100644 (file)
index f522bb8..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-Sharp Microelectronics 10.1" WQXGA TFT LCD panel
-
-This panel requires a dual-channel DSI host to operate. It supports two modes:
-- left-right: each channel drives the left or right half of the screen
-- even-odd: each channel drives the even or odd lines of the screen
-
-Each of the DSI channels controls a separate DSI peripheral. The peripheral
-driven by the first link (DSI-LINK1), left or even, is considered the primary
-peripheral and controls the device. The 'link2' property contains a phandle
-to the peripheral driven by the second link (DSI-LINK2, right or odd).
-
-Note that in video mode the DSI-LINK1 interface always provides the left/even
-pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it
-is possible to program either link to drive the left/even or right/odd pixels
-but for the sake of consistency this binding assumes that the same assignment
-is chosen as for video mode.
-
-Required properties:
-- compatible: should be "sharp,lq101r1sx01"
-- reg: DSI virtual channel of the peripheral
-
-Required properties (for DSI-LINK1 only):
-- link2: phandle to the DSI peripheral on the secondary link. Note that the
-  presence of this property marks the containing node as DSI-LINK1.
-- power-supply: phandle of the regulator that provides the supply voltage
-
-Optional properties (for DSI-LINK1 only):
-- backlight: phandle of the backlight device attached to the panel
-
-Example:
-
-       dsi@54300000 {
-               panel: panel@0 {
-                       compatible = "sharp,lq101r1sx01";
-                       reg = <0>;
-
-                       link2 = <&secondary>;
-
-                       power-supply = <...>;
-                       backlight = <...>;
-               };
-       };
-
-       dsi@54400000 {
-               secondary: panel@0 {
-                       compatible = "sharp,lq101r1sx01";
-                       reg = <0>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt b/Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt
deleted file mode 100644 (file)
index fc1ea9e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "shelly,sca07010-bfn-lnn"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt
deleted file mode 100644 (file)
index 1341bbf..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Simple display panel
-
-Required properties:
-- power-supply: regulator to provide the supply voltage
-
-Optional properties:
-- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- enable-gpios: GPIO pin to enable or disable the panel
-- backlight: phandle of the backlight device attached to the panel
-
-Example:
-
-       panel: panel {
-               compatible = "cptt,claa101wb01";
-               ddc-i2c-bus = <&panelddc>;
-
-               power-supply = <&vdd_pnl_reg>;
-               enable-gpios = <&gpio 90 0>;
-
-               backlight = <&backlight>;
-       };
diff --git a/Documentation/devicetree/bindings/pci/altera-pcie-msi.txt b/Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
new file mode 100644 (file)
index 0000000..09cd3bc
--- /dev/null
@@ -0,0 +1,28 @@
+* Altera PCIe MSI controller
+
+Required properties:
+- compatible:  should contain "altr,msi-1.0"
+- reg:         specifies the physical base address of the controller and
+               the length of the memory mapped region.
+- reg-names:   must include the following entries:
+               "csr": CSR registers
+               "vector_slave": vectors slave port region
+- interrupt-parent:    interrupt source phandle.
+- interrupts:  specifies the interrupt source of the parent interrupt
+               controller. The format of the interrupt specifier depends on the
+               parent interrupt controller.
+- num-vectors: number of vectors, range 1 to 32.
+- msi-controller:      indicates that this is MSI controller node
+
+
+Example
+msi0: msi@0xFF200000 {
+       compatible = "altr,msi-1.0";
+       reg = <0xFF200000 0x00000010
+               0xFF200010 0x00000080>;
+       reg-names = "csr", "vector_slave";
+       interrupt-parent = <&hps_0_arm_gic_0>;
+       interrupts = <0 42 4>;
+       msi-controller;
+       num-vectors = <32>;
+};
diff --git a/Documentation/devicetree/bindings/pci/altera-pcie.txt b/Documentation/devicetree/bindings/pci/altera-pcie.txt
new file mode 100644 (file)
index 0000000..2951a6a
--- /dev/null
@@ -0,0 +1,49 @@
+* Altera PCIe controller
+
+Required properties:
+- compatible : should contain "altr,pcie-root-port-1.0"
+- reg:         a list of physical base address and length for TXS and CRA.
+- reg-names:   must include the following entries:
+               "Txs": TX slave port region
+               "Cra": Control register access region
+- interrupt-parent:    interrupt source phandle.
+- interrupts:  specifies the interrupt source of the parent interrupt controller.
+               The format of the interrupt specifier depends on the parent interrupt
+               controller.
+- device_type: must be "pci"
+- #address-cells:      set to <3>
+- #size-cells: set to <2>
+- #interrupt-cells:    set to <1>
+- ranges:              describes the translation of addresses for root ports and standard
+               PCI regions.
+- interrupt-map-mask and interrupt-map: standard PCI properties to define the
+               mapping of the PCIe interface to interrupt numbers.
+
+Optional properties:
+- msi-parent:  Link to the hardware entity that serves as the MSI controller for this PCIe
+               controller.
+- bus-range:   PCI bus numbers covered
+
+Example
+       pcie_0: pcie@0xc00000000 {
+               compatible = "altr,pcie-root-port-1.0";
+               reg = <0xc0000000 0x20000000>,
+                       <0xff220000 0x00004000>;
+               reg-names = "Txs", "Cra";
+               interrupt-parent = <&hps_0_arm_gic_0>;
+               interrupts = <0 40 4>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               bus-range = <0x0 0xFF>;
+               device_type = "pci";
+               msi-parent = <&msi_to_gic_gen_0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_0 1>,
+                                   <0 0 0 2 &pcie_0 2>,
+                                   <0 0 0 3 &pcie_0 3>,
+                                   <0 0 0 4 &pcie_0 4>;
+               ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
+                           0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
+       };
index f7ce50e38ed495fdda7263878e1337b557632c5d..45c2a8094a9f7f7de65b37e41675bd0af4d6fe15 100644 (file)
@@ -17,6 +17,21 @@ Optional properties:
 - phys: phandle of the PCIe PHY device
 - phy-names: must be "pcie-phy"
 
+- brcm,pcie-ob: Some iProc SoCs do not have the outbound address mapping done
+by the ASIC after power on reset. In this case, SW needs to configure it
+
+If the brcm,pcie-ob property is present, the following properties become
+effective:
+
+Required:
+- brcm,pcie-ob-axi-offset: The offset from the AXI address to the internal
+address used by the iProc PCIe core (not the PCIe address)
+- brcm,pcie-ob-window-size: The outbound address mapping window size (in MB)
+
+Optional:
+- brcm,pcie-ob-oarr-size: Some iProc SoCs need the OARR size bit to be set to
+increase the outbound window size
+
 Example:
        pcie0: pcie@18012000 {
                compatible = "brcm,iproc-pcie";
@@ -38,6 +53,11 @@ Example:
 
                phys = <&phy 0 5>;
                phy-names = "pcie-phy";
+
+               brcm,pcie-ob;
+               brcm,pcie-ob-oarr-size;
+               brcm,pcie-ob-axi-offset = <0x00000000>;
+               brcm,pcie-ob-window-size = <256>;
        };
 
        pcie1: pcie@18013000 {
index 9f4faa8e8d005ee1810f0dc4272d63f4af3e17e6..5b0853df9d5a4c0da73e8bdf07e115d08fd8b28b 100644 (file)
@@ -15,14 +15,16 @@ Required properties:
        to define the mapping of the PCIe interface to interrupt
        numbers.
 - num-lanes: number of lanes to use
-- clocks: Must contain an entry for each entry in clock-names.
-       See ../clocks/clock-bindings.txt for details.
-- clock-names: Must include the following entries:
-       - "pcie"
-       - "pcie_bus"
 
 Optional properties:
+- num-lanes: number of lanes to use (this property should be specified unless
+  the link is brought already up in BIOS)
 - reset-gpio: gpio pin number of power good signal
 - bus-range: PCI bus numbers covered (it is recommended for new devicetrees to
   specify this property, to keep backwards compatibility a range of 0x00-0xff
   is assumed if not present)
+- clocks: Must contain an entry for each entry in clock-names.
+       See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+       - "pcie"
+       - "pcie_bus"
diff --git a/Documentation/devicetree/bindings/pci/hisilicon-pcie.txt b/Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
new file mode 100644 (file)
index 0000000..17c6ed9
--- /dev/null
@@ -0,0 +1,44 @@
+HiSilicon PCIe host bridge DT description
+
+HiSilicon PCIe host controller is based on Designware PCI core.
+It shares common functions with PCIe Designware core driver and inherits
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt.
+
+Additional properties are described here:
+
+Required properties:
+- compatible: Should contain "hisilicon,hip05-pcie".
+- reg: Should contain rc_dbi, config registers location and length.
+- reg-names: Must include the following entries:
+  "rc_dbi": controller configuration registers;
+  "config": PCIe configuration space registers.
+- msi-parent: Should be its_pcie which is an ITS receiving MSI interrupts.
+- port-id: Should be 0, 1, 2 or 3.
+
+Optional properties:
+- status: Either "ok" or "disabled".
+- dma-coherent: Present if DMA operations are coherent.
+
+Example:
+       pcie@0xb0080000 {
+               compatible = "hisilicon,hip05-pcie", "snps,dw-pcie";
+               reg = <0 0xb0080000 0 0x10000>, <0x220 0x00000000 0 0x2000>;
+               reg-names = "rc_dbi", "config";
+               bus-range = <0  15>;
+               msi-parent = <&its_pcie>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               dma-coherent;
+               ranges = <0x82000000 0 0x00000000 0x220 0x00000000 0 0x10000000>;
+               num-lanes = <8>;
+               port-id = <1>;
+               #interrupts-cells = <1>;
+               interrupts-map-mask = <0xf800 0 0 7>;
+               interrupts-map = <0x0 0 0 1 &mbigen_pcie 1 10
+                                 0x0 0 0 2 &mbigen_pcie 2 11
+                                 0x0 0 0 3 &mbigen_pcie 3 12
+                                 0x0 0 0 4 &mbigen_pcie 4 13>;
+               status = "ok";
+       };
index cf3e205e0b7e0de18e8e6650bdc347d996807960..3f1d3fca62bbf6a62afd1d270d271582c6c2e20e 100644 (file)
@@ -34,8 +34,9 @@ Properties of the host controller node:
 - #size-cells    : Must be 2.
 
 - reg            : The Configuration Space base address and size, as accessed
-                   from the parent bus.
-
+                   from the parent bus.  The base address corresponds to
+                   the first bus in the "bus-range" property.  If no
+                   "bus-range" is specified, this will be bus 0 (the default).
 
 Properties of the /chosen node:
 
index 6286f049bf189599346ee6a05d31392e132abf5e..e3767857d30df98ef8a8d1b658e56bb6f6afadef 100644 (file)
@@ -1,10 +1,20 @@
 Freescale Layerscape PCIe controller
 
-This PCIe host controller is based on the Synopsis Designware PCIe IP
+This PCIe host controller is based on the Synopsys DesignWare PCIe IP
 and thus inherits all the common properties defined in designware-pcie.txt.
 
+This controller derives its clocks from the Reset Configuration Word (RCW)
+which is used to describe the PLL settings at the time of chip-reset.
+
+Also as per the available Reference Manuals, there is no specific 'version'
+register available in the Freescale PCIe controller register set,
+which can allow determining the underlying DesignWare PCIe controller version
+information.
+
 Required properties:
-- compatible: should contain the platform identifier such as "fsl,ls1021a-pcie"
+- compatible: should contain the platform identifier such as:
+        "fsl,ls1021a-pcie", "snps,dw-pcie"
+        "fsl,ls2080a-pcie", "snps,dw-pcie"
 - reg: base addresses and lengths of the PCIe controller
 - interrupts: A list of interrupt outputs of the controller. Must contain an
   entry for each entry in the interrupt-names property.
index f8fbe9af7b2f276350426b299c6030adb9464640..08dcfad09f8d7bdfd60e5254ef98aa42ed07a11d 100644 (file)
@@ -1,12 +1,12 @@
 PCI bus bridges have standardized Device Tree bindings:
 
 PCI Bus Binding to: IEEE Std 1275-1994
-http://www.openfirmware.org/ofwg/bindings/pci/pci2_1.pdf
+http://www.firmware.org/1275/bindings/pci/pci2_1.pdf
 
 And for the interrupt mapping part:
 
 Open Firmware Recommended Practice: Interrupt Mapping
-http://www.openfirmware.org/1275/practice/imap/imap0_9d.pdf
+http://www.firmware.org/1275/practice/imap/imap0_9d.pdf
 
 Additionally to the properties specified in the above standards a host bridge
 driver implementation may support the following properties:
diff --git a/Documentation/devicetree/bindings/phy/calxeda-combophy.txt b/Documentation/devicetree/bindings/phy/calxeda-combophy.txt
new file mode 100644 (file)
index 0000000..6622bdb
--- /dev/null
@@ -0,0 +1,17 @@
+Calxeda Highbank Combination Phys for SATA
+
+Properties:
+- compatible : Should be "calxeda,hb-combophy"
+- #phy-cells: Should be 1.
+- reg : Address and size for Combination Phy registers.
+- phydev: device ID for programming the combophy.
+
+Example:
+
+       combophy5: combo-phy@fff5d000 {
+               compatible = "calxeda,hb-combophy";
+               #phy-cells = <1>;
+               reg = <0xfff5d000 0x1000>;
+               phydev = <31>;
+       };
+
diff --git a/Documentation/devicetree/bindings/phy/keystone-usb-phy.txt b/Documentation/devicetree/bindings/phy/keystone-usb-phy.txt
new file mode 100644 (file)
index 0000000..f37b3a8
--- /dev/null
@@ -0,0 +1,20 @@
+TI Keystone USB PHY
+
+Required properties:
+ - compatible: should be "ti,keystone-usbphy".
+ - #address-cells, #size-cells : should be '1' if the device has sub-nodes
+   with 'reg' property.
+ - reg : Address and length of the usb phy control register set.
+
+The main purpose of this PHY driver is to enable the USB PHY reference clock
+gate on the Keystone SOC for both the USB2 and USB3 PHY. Otherwise it is just
+an NOP PHY driver.  Hence this node is referenced as both the usb2 and usb3
+phy node in the USB Glue layer driver node.
+
+usb_phy: usb_phy@2620738 {
+       compatible = "ti,keystone-usbphy";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       reg = <0x2620738 32>;
+       status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
new file mode 100644 (file)
index 0000000..379b84a
--- /dev/null
@@ -0,0 +1,21 @@
+* Freescale MXS USB Phy Device
+
+Required properties:
+- compatible: should contain:
+       * "fsl,imx23-usbphy" for imx23 and imx28
+       * "fsl,imx6q-usbphy" for imx6dq and imx6dl
+       * "fsl,imx6sl-usbphy" for imx6sl
+       * "fsl,vf610-usbphy" for Vybrid vf610
+       * "fsl,imx6sx-usbphy" for imx6sx
+  "fsl,imx23-usbphy" is still a fallback for other strings
+- reg: Should contain registers location and length
+- interrupts: Should contain phy interrupt
+- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
+
+Example:
+usbphy1: usbphy@020c9000 {
+       compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
+       reg = <0x020c9000 0x1000>;
+       interrupts = <0 44 0x04>;
+       fsl,anatop = <&anatop>;
+};
diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/phy/nvidia,tegra20-usb-phy.txt
new file mode 100644 (file)
index 0000000..a9aa79f
--- /dev/null
@@ -0,0 +1,72 @@
+Tegra SOC USB PHY
+
+The device node for Tegra SOC USB PHY:
+
+Required properties :
+ - compatible : For Tegra20, must contain "nvidia,tegra20-usb-phy".
+   For Tegra30, must contain "nvidia,tegra30-usb-phy".  Otherwise, must contain
+   "nvidia,<chip>-usb-phy" plus at least one of the above, where <chip> is
+   tegra114, tegra124, tegra132, or tegra210.
+ - reg : Defines the following set of registers, in the order listed:
+   - The PHY's own register set.
+     Always present.
+   - The register set of the PHY containing the UTMI pad control registers.
+     Present if-and-only-if phy_type == utmi.
+ - phy_type : Should be one of "utmi", "ulpi" or "hsic".
+ - clocks : Defines the clocks listed in the clock-names property.
+ - clock-names : The following clock names must be present:
+   - reg: The clock needed to access the PHY's own registers. This is the
+     associated EHCI controller's clock. Always present.
+   - pll_u: PLL_U. Always present.
+   - timer: The timeout clock (clk_m). Present if phy_type == utmi.
+   - utmi-pads: The clock needed to access the UTMI pad control registers.
+     Present if phy_type == utmi.
+   - ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2).
+     Present if phy_type == ulpi, and ULPI link mode is in use.
+ - resets : Must contain an entry for each entry in reset-names.
+   See ../reset/reset.txt for details.
+ - reset-names : Must include the following entries:
+   - usb: The PHY's own reset signal.
+   - utmi-pads: The reset of the PHY containing the chip-wide UTMI pad control
+     registers. Required even if phy_type == ulpi.
+
+Required properties for phy_type == ulpi:
+  - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
+
+Required PHY timing params for utmi phy, for all chips:
+  - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
+    start of sync launches RxActive
+  - nvidia,elastic-limit : Variable FIFO Depth of elastic input store
+  - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
+    before declare IDLE.
+  - nvidia,term-range-adj : Range adjusment on terminations
+  - Either one of the following for HS driver output control:
+    - nvidia,xcvr-setup : integer, uses the provided value.
+    - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read
+      from the on-chip fuses
+    If both are provided, nvidia,xcvr-setup-use-fuses takes precedence.
+  - nvidia,xcvr-lsfslew : LS falling slew rate control.
+  - nvidia,xcvr-lsrslew :  LS rising slew rate control.
+
+Required PHY timing params for utmi phy, only on Tegra30 and above:
+  - nvidia,xcvr-hsslew : HS slew rate control.
+  - nvidia,hssquelch-level : HS squelch detector level.
+  - nvidia,hsdiscon-level : HS disconnect detector level.
+
+Optional properties:
+  - nvidia,has-legacy-mode : boolean indicates whether this controller can
+    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
+    registers are accessed through the APB_MISC base address instead of
+    the USB controller.
+  - nvidia,is-wired : boolean. Indicates whether we can do certain kind of power
+    optimizations for the devices that are always connected. e.g. modem.
+  - dr_mode : dual role mode. Indicates the working mode for the PHY. Can be
+    "host", "peripheral", or "otg". Defaults to "host" if not defined.
+      host means this is a host controller
+      peripheral means it is device controller
+      otg means it can operate as either ("on the go")
+  - nvidia,has-utmi-pad-registers : boolean indicates whether this controller
+    contains the UTMI pad control registers common to all USB controllers.
+
+VBUS control (required for dr_mode == otg, optional for dr_mode == host):
+  - vbus-supply: regulator for VBUS
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-8x16-phy.txt
new file mode 100644 (file)
index 0000000..2cb2168
--- /dev/null
@@ -0,0 +1,76 @@
+Qualcomm's APQ8016/MSM8916 USB transceiver controller
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,usb-8x16-phy".
+
+- reg:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: USB PHY base address and length of the register map
+
+- clocks:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: See clock-bindings.txt section "consumers". List of
+                two clock specifiers for interface and core controller
+                clocks.
+
+- clock-names:
+    Usage: required
+    Value type: <string>
+    Definition: Must contain "iface" and "core" strings.
+
+- vddcx-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator VDCCX supply node.
+
+- v1p8-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator 1.8V supply node.
+
+- v3p3-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator 3.3V supply node.
+
+- resets:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: See reset.txt section "consumers". PHY reset specifier.
+
+- reset-names:
+    Usage: required
+    Value type: <string>
+    Definition: Must contain "phy" string.
+
+- switch-gpio:
+    Usage: optional
+    Value type: <prop-encoded-array>
+    Definition: Some boards are using Dual SPDT USB Switch, witch is
+                controlled by GPIO to de/multiplex D+/D- USB lines
+                between connectors.
+
+Example:
+       usb_phy: phy@78d9000 {
+               compatible = "qcom,usb-8x16-phy";
+               reg = <0x78d9000 0x400>;
+
+               vddcx-supply = <&pm8916_s1_corner>;
+               v1p8-supply = <&pm8916_l7>;
+               v3p3-supply = <&pm8916_l13>;
+
+               clocks = <&gcc GCC_USB_HS_AHB_CLK>,
+                            <&gcc GCC_USB_HS_SYSTEM_CLK>;
+               clock-names = "iface", "core";
+
+               resets = <&gcc GCC_USB2A_PHY_BCR>;
+               reset-names = "phy";
+
+               // D+/D- lines: 1 - Routed to HUB, 0 - Device connector
+               switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>;
+       };
+
diff --git a/Documentation/devicetree/bindings/power/wakeup-source.txt b/Documentation/devicetree/bindings/power/wakeup-source.txt
new file mode 100644 (file)
index 0000000..963c6df
--- /dev/null
@@ -0,0 +1,71 @@
+Specifying wakeup capability for devices
+============================================
+
+Any device nodes
+----------------
+Nodes that describe devices which has wakeup capability must contain an
+"wakeup-source" boolean property.
+
+Also, if device is marked as a wakeup source, then all the primary
+interrupt(s) can be used as wakeup interrupt(s).
+
+However if the devices have dedicated interrupt as the wakeup source
+then they need to specify/identify the same using device specific
+interrupt name. In such cases only that interrupt can be used as wakeup
+interrupt.
+
+List of legacy properties and respective binding document
+---------------------------------------------------------
+
+1. "enable-sdio-wakeup"                Documentation/devicetree/bindings/mmc/mmc.txt
+2. "gpio-key,wakeup"           Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
+3. "has-tpo"                   Documentation/devicetree/bindings/rtc/rtc-opal.txt
+4. "isil,irq2-can-wakeup-machine" Documentation/devicetree/bindings/rtc/isil,isl12057.txt
+5. "linux,wakeup"              Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
+                               Documentation/devicetree/bindings/mfd/tc3589x.txt
+                               Documentation/devicetree/bindings/input/ads7846.txt
+6. "linux,keypad-wakeup"       Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
+7. "linux,input-wakeup"                Documentation/devicetree/bindings/input/samsung-keypad.txt
+8. "nvidia,wakeup-source"      Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
+
+Examples
+--------
+
+1. With "wakeup" interrupt name
+
+       device@10000 {
+               compatible      = "vendor,device-id";
+               reg             = <0x10000 0x1000>;
+               interrupts      = <0 19 4>, <0 21 4>, <0 22 4>;
+               interrupt-names = "ack", "err", "wakeup";
+               wakeup-source;
+       };
+
+2. Without "wakeup" interrupt name
+
+       embedded-controller {
+               compatible = "google,cros-ec-i2c";
+               reg = <0x1e>;
+               interrupts = <6 0>;
+               interrupt-parent = <&gpx1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ec_irq>;
+               wakeup-source;
+       };
+
+3. Without interrupts
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               button@1 {
+                       debounce_interval = <50>;
+                       wakeup-source;
+                       linux,code = <116>;
+                       label = "POWER";
+                       gpios = <&iofpga_gpio0 0 0x4>;
+               };
+               [....]
+       };
diff --git a/Documentation/devicetree/bindings/rng/atmel-trng.txt b/Documentation/devicetree/bindings/rng/atmel-trng.txt
new file mode 100644 (file)
index 0000000..4ac5aaa
--- /dev/null
@@ -0,0 +1,16 @@
+Atmel TRNG (True Random Number Generator) block
+
+Required properties:
+- compatible : Should be "atmel,at91sam9g45-trng"
+- reg : Offset and length of the register set of this block
+- interrupts : the interrupt number for the TRNG block
+- clocks: should contain the TRNG clk source
+
+Example:
+
+trng@fffcc000 {
+       compatible = "atmel,at91sam9g45-trng";
+       reg = <0xfffcc000 0x4000>;
+       interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>;
+       clocks = <&trng_clk>;
+};
diff --git a/Documentation/devicetree/bindings/rng/brcm,iproc-rng200.txt b/Documentation/devicetree/bindings/rng/brcm,iproc-rng200.txt
new file mode 100644 (file)
index 0000000..e25a456
--- /dev/null
@@ -0,0 +1,12 @@
+HWRNG support for the iproc-rng200 driver
+
+Required properties:
+- compatible : "brcm,iproc-rng200"
+- reg : base address and size of control register block
+
+Example:
+
+rng {
+        compatible = "brcm,iproc-rng200";
+        reg = <0x18032000 0x28>;
+};
diff --git a/Documentation/devicetree/bindings/rng/omap_rng.txt b/Documentation/devicetree/bindings/rng/omap_rng.txt
new file mode 100644 (file)
index 0000000..6a62acd
--- /dev/null
@@ -0,0 +1,22 @@
+OMAP SoC HWRNG Module
+
+Required properties:
+
+- compatible : Should contain entries for this and backward compatible
+  RNG versions:
+  - "ti,omap2-rng" for OMAP2.
+  - "ti,omap4-rng" for OMAP4, OMAP5 and AM33XX.
+  Note that these two versions are incompatible.
+- ti,hwmods: Name of the hwmod associated with the RNG module
+- reg : Offset and length of the register set for the module
+- interrupts : the interrupt number for the RNG module.
+               Only used for "ti,omap4-rng".
+
+Example:
+/* AM335x */
+rng: rng@48310000 {
+       compatible = "ti,omap4-rng";
+       ti,hwmods = "rng";
+       reg = <0x48310000 0x2000>;
+       interrupts = <111>;
+};
diff --git a/Documentation/devicetree/bindings/rng/timeriomem_rng.txt b/Documentation/devicetree/bindings/rng/timeriomem_rng.txt
new file mode 100644 (file)
index 0000000..6616d15
--- /dev/null
@@ -0,0 +1,18 @@
+HWRNG support for the timeriomem_rng driver
+
+Required properties:
+- compatible : "timeriomem_rng"
+- reg : base address to sample from
+- period : wait time in microseconds to use between samples
+
+N.B. currently 'reg' must be four bytes wide and aligned
+
+Example:
+
+hwrng@44 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "timeriomem_rng";
+       reg = <0x44 0x04>;
+       period = <1000000>;
+};
index 501c39ceae795e7c784c1fd3c2fd3781aaa86260..cf83e0940302cbf3b1795be0a06df1a8191220ef 100644 (file)
@@ -5,7 +5,7 @@ consisting of a compatible field, an address and possibly an interrupt
 line).
 
 Nonetheless, it also supports an option boolean property
-("isil,irq2-can-wakeup-machine") to handle the specific use-case found
+("wakeup-source") to handle the specific use-case found
 on at least three in-tree users of the chip (NETGEAR ReadyNAS 102, 104
 and 2120 ARM-based NAS); On those devices, the IRQ#2 pin of the chip
 (associated with the alarm supported by the driver) is not connected
@@ -22,9 +22,9 @@ Required properties supported by the device:
 
 Optional properties:
 
- - "isil,irq2-can-wakeup-machine": mark the chip as a wakeup source,
-   independently of the availability of an IRQ line connected to the
-   SoC.
+ - "wakeup-source": mark the chip as a wakeup source, independently of
+    the availability of an IRQ line connected to the SoC.
+    (Legacy property supported: "isil,irq2-can-wakeup-machine")
 
  - "interrupt-parent", "interrupts": for passing the interrupt line
    of the SoC connected to IRQ#2 of the RTC chip.
@@ -74,5 +74,5 @@ PMIC, allowing the device to be started based on configured alarm:
        isl12057: isl12057@68 {
                compatible = "isil,isl12057";
                reg = <0x68>;
-               isil,irq2-can-wakeup-machine;
+               wakeup-source;
        };
index af87e5ecac540ce965c3e8ec0f36900d9f3e4ccb..a1734e5cb75bb6279beef456f6acf2fdef043045 100644 (file)
@@ -5,12 +5,13 @@ Required properties:
 - comapatible: Should be "ibm,opal-rtc"
 
 Optional properties:
-- has-tpo: Decides if the wakeup is supported or not.
+- wakeup-source: Decides if the wakeup is supported or not
+                (Legacy property supported: "has-tpo")
 
 Example:
        rtc {
                compatible = "ibm,opal-rtc";
-               has-tpo;
+               wakeup-source;
                phandle = <0x10000029>;
                linux,phandle = <0x10000029>;
        };
index 669b8140dd796db70aa738a451e15d2199a335a3..d10cc06c0c37e1389ba9ba996924e68b1e505aba 100644 (file)
@@ -10,7 +10,6 @@ Required properties:
                                mvrl,pxa168-ssp
                                mrvl,pxa910-ssp
                                mrvl,ce4100-ssp
-                               mrvl,lpss-ssp
 
        - reg:          The memory base
        - dmas:         Two dma phandles, one for rx, one for tx
diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt
new file mode 100644 (file)
index 0000000..15a9195
--- /dev/null
@@ -0,0 +1,17 @@
+AK4613 I2C transmitter
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak4613"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+       ak4613: ak4613@0x10 {
+               compatible = "asahi-kasei,ak4613";
+               reg = <0x10>;
+       };
+};
index 623d4e70ae11d9ef5ee6231c09f0e8293fb32680..340784db6808809eecf4ae0e310023550713e2c6 100644 (file)
@@ -7,7 +7,14 @@ Required properties:
   - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
   - reg : The chip select number on the I2C bus
 
-Example:
+Optional properties:
+
+  - #clock-cells :             common clock binding; shall be set to 0
+  - clocks :                   common clock binding; MCKI clock
+  - clock-frequency :          common clock binding; frequency of MCKO
+  - clock-output-names :       common clock binding; MCKO clock name
+
+Example 1:
 
 &i2c {
        ak4648: ak4648@0x12 {
@@ -15,3 +22,16 @@ Example:
                reg = <0x12>;
        };
 };
+
+Example 2:
+
+&i2c {
+       ak4643: codec@12 {
+               compatible = "asahi-kasei,ak4643";
+               reg = <0x12>;
+               #clock-cells = <0>;
+               clocks = <&audio_clock>;
+               clock-frequency = <12288000>;
+               clock-output-names = "ak4643_mcko";
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-classd.txt b/Documentation/devicetree/bindings/sound/atmel-classd.txt
new file mode 100644 (file)
index 0000000..0018451
--- /dev/null
@@ -0,0 +1,52 @@
+* Atmel ClassD driver under ALSA SoC architecture
+
+Required properties:
+- compatible
+       Should be "atmel,sama5d2-classd".
+- reg
+       Should contain ClassD registers location and length.
+- interrupts
+       Should contain the IRQ line for the ClassD.
+- dmas
+       One DMA specifiers as described in atmel-dma.txt and dma.txt files.
+- dma-names
+       Must be "tx".
+- clock-names
+       Tuple listing input clock names.
+       Required elements: "pclk", "gclk" and "aclk".
+- clocks
+       Please refer to clock-bindings.txt.
+
+Optional properties:
+- pinctrl-names, pinctrl-0
+       Please refer to pinctrl-bindings.txt.
+- atmel,model
+       The user-visible name of this sound complex.
+       The default value is "CLASSD".
+- atmel,pwm-type
+       PWM modulation type, "single" or "diff".
+       The default value is "single".
+- atmel,non-overlap-time
+       Set non-overlapping time, the unit is nanosecond(ns).
+       There are four values,
+       <5>, <10>, <15>, <20>, the default value is <10>.
+       Non-overlapping will be disabled if not specified.
+
+Example:
+classd: classd@fc048000 {
+               compatible = "atmel,sama5d2-classd";
+               reg = <0xfc048000 0x100>;
+               interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
+               dmas = <&dma0
+                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                       | AT91_XDMAC_DT_PERID(47))>;
+               dma-names = "tx";
+               clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
+               clock-names = "pclk", "gclk", "aclk";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_classd_default>;
+               atmel,model = "classd @ SAMA5D2-Xplained";
+               atmel,pwm-type = "diff";
+               atmel,non-overlap-time = <10>;
+};
diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt
new file mode 100644 (file)
index 0000000..5890280
--- /dev/null
@@ -0,0 +1,41 @@
+Dialog Semiconductor DA7213 Audio Codec bindings
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7213"
+- reg: Specifies the I2C slave address
+
+Optional properties:
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1
+       [<1600>, <2200>, <2500>, <3000>]
+- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2
+       [<1600>, <2200>, <2500>, <3000>]
+- dlg,dmic-data-sel : DMIC channel select based on clock edge.
+       ["lrise_rfall", "lfall_rrise"]
+- dlg,dmic-samplephase : When to sample audio from DMIC.
+       ["on_clkedge", "between_clkedge"]
+- dlg,dmic-clkrate : DMIC clock frequency (Hz).
+       [<1500000>, <3000000>]
+
+======
+
+Example:
+
+       codec_i2c: da7213@1a {
+               compatible = "dlg,da7213";
+               reg = <0x1a>;
+
+               clocks = <&clks 201>;
+               clock-names = "mclk";
+
+               dlg,micbias1-lvl = <2500>;
+               dlg,micbias2-lvl = <2500>;
+
+               dlg,dmic-data-sel = "lrise_rfall";
+               dlg,dmic-samplephase = "between_clkedge";
+               dlg,dmic-clkrate = <3000000>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt
new file mode 100644 (file)
index 0000000..1b70309
--- /dev/null
@@ -0,0 +1,106 @@
+Dialog Semiconductor DA7219 Audio Codec bindings
+
+DA7219 is an audio codec with advanced accessory detect features.
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7219"
+- reg: Specifies the I2C slave address
+
+- interrupt-parent : Specifies the phandle of the interrupt controller to which
+  the IRQs from DA7219 are delivered to.
+- interrupts : IRQ line info for DA7219.
+  (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+   further information relating to interrupt properties)
+
+- VDD-supply: VDD power supply for the device
+- VDDMIC-supply: VDDMIC power supply for the device
+- VDDIO-supply: VDDIO power supply for the device
+  (See Documentation/devicetree/bindings/regulator/regulator.txt for further
+   information relating to regulators)
+
+Optional properties:
+- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
+  interrupt is to be used to wake system, otherwise "irq" should be used.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
+
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
+       [<1050>, <1100>, <1200>, <1400>]
+- dlg,micbias-lvl : Voltage (mV) for Mic Bias
+       [<1800>, <2000>, <2200>, <2400>, <2600>]
+- dlg,mic-amp-in-sel : Mic input source type
+       ["diff", "se_p", "se_n"]
+
+======
+
+Child node - 'da7219_aad':
+
+Optional properties:
+- dlg,micbias-pulse-lvl : Mic bias higher voltage pulse level (mV).
+       [<2800>, <2900>]
+- dlg,micbias-pulse-time : Mic bias higher voltage pulse duration (ms)
+- dlg,btn-cfg : Periodic button press measurements for 4-pole jack (ms)
+       [<2>, <5>, <10>, <50>, <100>, <200>, <500>]
+- dlg,mic-det-thr : Impedance threshold for mic detection measurement (Ohms)
+       [<200>, <500>, <750>, <1000>]
+- dlg,jack-ins-deb : Debounce time for jack insertion (ms)
+       [<5>, <10>, <20>, <50>, <100>, <200>, <500>, <1000>]
+- dlg,jack-det-rate: Jack type detection latency (3/4 pole)
+       ["32ms_64ms", "64ms_128ms", "128ms_256ms", "256ms_512ms"]
+- dlg,jack-rem-deb : Debounce time for jack removal (ms)
+       [<1>, <5>, <10>, <20>]
+- dlg,a-d-btn-thr : Impedance threshold between buttons A and D
+       [0x0 - 0xFF]
+- dlg,d-b-btn-thr : Impedance threshold between buttons D and B
+       [0x0 - 0xFF]
+- dlg,b-c-btn-thr : Impedance threshold between buttons B and C
+       [0x0 - 0xFF]
+- dlg,c-mic-btn-thr : Impedance threshold between button C and Mic
+       [0x0 - 0xFF]
+- dlg,btn-avg : Number of 8-bit readings for averaged button measurement
+       [<1>, <2>, <4>, <8>]
+- dlg,adc-1bit-rpt : Repeat count for 1-bit button measurement
+       [<1>, <2>, <4>, <8>]
+
+======
+
+Example:
+
+       codec: da7219@1a {
+               compatible = "dlg,da7219";
+               reg = <0x1a>;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+
+               VDD-supply = <&reg_audio>;
+               VDDMIC-supply = <&reg_audio>;
+               VDDIO-supply = <&reg_audio>;
+
+               clocks = <&clks 201>;
+               clock-names = "mclk";
+
+               dlg,ldo-lvl = <1200>;
+               dlg,micbias-lvl = <2600>;
+               dlg,mic-amp-in-sel = "diff";
+
+               da7219_aad {
+                       dlg,btn-cfg = <50>;
+                       dlg,mic-det-thr = <500>;
+                       dlg,jack-ins-deb = <20>;
+                       dlg,jack-det-rate = "32ms_64ms";
+                       dlg,jack-rem-deb = <1>;
+
+                       dlg,a-d-btn-thr = <0xa>;
+                       dlg,d-b-btn-thr = <0x16>;
+                       dlg,b-c-btn-thr = <0x21>;
+                       dlg,c-mic-btn-thr = <0x3E>;
+
+                       dlg,btn-avg = <4>;
+                       dlg,adc-1bit-rpt = <1>;
+               };
+       };
index a96774c194c8be9f242c1db4ca0398283e10a203..ce55c0a6f7578ee192a207a6b247095d605072b8 100644 (file)
@@ -13,13 +13,15 @@ So having this generic sound card allows all Freescale SoC users to benefit
 from the simplification of a new card support and the capability of the wide
 sample rates support through ASRC.
 
-Note: The card is initially designed for those sound cards who use I2S and
-      PCM DAI formats. However, it'll be also possible to support those non
-      I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
-      as the driver has been properly upgraded.
+Note: The card is initially designed for those sound cards who use AC'97, I2S
+      and PCM DAI formats. However, it'll be also possible to support those non
+      AC'97/I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as
+      long as the driver has been properly upgraded.
 
 
 The compatible list for this generic sound card currently:
+ "fsl,imx-audio-ac97"
+
  "fsl,imx-audio-cs42888"
 
  "fsl,imx-audio-wm8962"
diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt
new file mode 100644 (file)
index 0000000..d337423
--- /dev/null
@@ -0,0 +1,102 @@
+Nuvoton NAU8825 audio codec
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "nuvoton,nau8825"
+
+  - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1).
+
+Optional properties:
+  - nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
+  - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
+      otherwise pin in high impedance state.
+  - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
+  - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
+
+  - nuvoton,vref-impedance: VREF Impedance selection
+      0 - Open
+      1 - 25 kOhm
+      2 - 125 kOhm
+      3 - 2.5 kOhm
+
+  - nuvoton,micbias-voltage: Micbias voltage level.
+      0 - VDDA
+      1 - VDDA
+      2 - VDDA * 1.1
+      3 - VDDA * 1.2
+      4 - VDDA * 1.3
+      5 - VDDA * 1.4
+      6 - VDDA * 1.53
+      7 - VDDA * 1.53
+
+  - nuvoton,sar-threshold-num: Number of buttons supported
+  - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as
+    SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R)
+    where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance.
+    Refer datasheet section 10.2 for more information about threshold calculation.
+
+  - nuvoton,sar-hysteresis: Button impedance measurement hysteresis.
+
+  - nuvoton,sar-voltage: Reference voltage for button impedance measurement.
+      0 - VDDA
+      1 - VDDA
+      2 - VDDA * 1.1
+      3 - VDDA * 1.2
+      4 - VDDA * 1.3
+      5 - VDDA * 1.4
+      6 - VDDA * 1.53
+      7 - VDDA * 1.53
+
+  - nuvoton,sar-compare-time: SAR compare time
+      0 - 500 ns
+      1 - 1 us
+      2 - 2 us
+      3 - 4 us
+
+  - nuvoton,sar-sampling-time: SAR sampling time
+      0 - 2 us
+      1 - 4 us
+      2 - 8 us
+      3 - 16 us
+
+  - nuvoton,short-key-debounce: Button short key press debounce time.
+      0 - 30 ms
+      1 - 50 ms
+      2 - 100 ms
+      3 - 30 ms
+
+  - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
+  - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
+
+  - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
+      clocks described in clock-names
+  - clock-names: should include "mclk" for the MCLK master clock
+
+Example:
+
+  headset: nau8825@1a {
+      compatible = "nuvoton,nau8825";
+      reg = <0x1a>;
+      interrupt-parent = <&gpio>;
+      interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
+      nuvoton,jkdet-enable;
+      nuvoton,jkdet-pull-enable;
+      nuvoton,jkdet-pull-up;
+      nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+      nuvoton,vref-impedance = <2>;
+      nuvoton,micbias-voltage = <6>;
+      // Setup 4 buttons impedance according to Android specification
+      nuvoton,sar-threshold-num = <4>;
+      nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>;
+      nuvoton,sar-hysteresis = <1>;
+      nuvoton,sar-voltage = <0>;
+      nuvoton,sar-compare-time = <0>;
+      nuvoton,sar-sampling-time = <0>;
+      nuvoton,short-key-debounce = <2>;
+      nuvoton,jack-insert-debounce = <7>;
+      nuvoton,jack-eject-debounce = <7>;
+
+      clock-names = "mclk";
+      clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+  };
index 1173395b5e5c16c070885b06ae06100eb0aa7ff2..c57cbd65736cfaf4bd67c0801fcd86dca19ef106 100644 (file)
@@ -4,10 +4,12 @@ Required properties:
 - compatible                   : "renesas,rcar_sound-<soctype>", fallbacks
                                  "renesas,rcar_sound-gen1" if generation1, and
                                  "renesas,rcar_sound-gen2" if generation2
+                                 "renesas,rcar_sound-gen3" if generation3
                                  Examples with soctypes are:
                                    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
                                    - "renesas,rcar_sound-r8a7790" (R-Car H2)
                                    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
+                                   - "renesas,rcar_sound-r8a7795" (R-Car H3)
 - reg                          : Should contain the register physical address.
                                  required register is
                                   SRU/ADG/SSI      if generation1
@@ -30,6 +32,11 @@ Required properties:
 - rcar_sound,dai               : DAI contents.
                                  The number of DAI subnode should be same as HW.
                                  see below for detail.
+- #sound-dai-cells             : it must be 0 if your system is using single DAI
+                                 it must be 1 if your system is using multi  DAI
+- #clock-cells                 : it must be 0 if your system has audio_clkout
+                                 it must be 1 if your system has audio_clkout0/1/2/3
+- clock-frequency              : for all audio_clkout0/1/2/3
 
 SSI subnode properties:
 - interrupts                   : Should contain SSI interrupt for PIO transfer
index 9b82c20b306bb1e10e6bf8be84dc2a9c97933438..2267d249ca0ee20959b525d1d2075e9e09909d9e 100644 (file)
@@ -12,8 +12,6 @@ Required properties:
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
-- #address-cells: should be 1.
-- #size-cells: should be 0.
 - dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
        Documentation/devicetree/bindings/dma/dma.txt
 - dma-names: should include "tx" and "rx".
@@ -21,6 +19,7 @@ Required properties:
 - clock-names: should contain followings:
    - "i2s_hclk": clock for I2S BUS
    - "i2s_clk" : clock for I2S controller
+- rockchip,capture-channels: max capture channels, if not set, 2 channels default.
 
 Example for rk3288 I2S controller:
 
@@ -28,10 +27,9 @@ i2s@ff890000 {
        compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
        reg = <0xff890000 0x10000>;
        interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
-       #address-cells = <1>;
-       #size-cells = <0>;
        dmas = <&pdma1 0>, <&pdma1 1>;
        dma-names = "tx", "rx";
        clock-names = "i2s_hclk", "i2s_clk";
        clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+       rockchip,capture-channels = <2>;
 };
diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt
new file mode 100644 (file)
index 0000000..e64dbde
--- /dev/null
@@ -0,0 +1,40 @@
+* Rockchip SPDIF transceiver
+
+The S/PDIF audio block is a stereo transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+- compatible: should be one of the following:
+   - "rockchip,rk3288-spdif", "rockchip,rk3188-spdif" or
+     "rockchip,rk3066-spdif"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: should contain the SPDIF interrupt.
+- dmas: DMA specifiers for tx dma. See the DMA client binding,
+  Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: should be "tx"
+- clocks: a list of phandle + clock-specifier pairs, one for each entry
+  in clock-names.
+- clock-names: should contain following:
+   - "hclk": clock for SPDIF controller
+   - "mclk" : clock for SPDIF bus
+
+Required properties on RK3288:
+  - rockchip,grf: the phandle of the syscon node for the general register
+                   file (GRF)
+
+Example for the rk3188 SPDIF controller:
+
+spdif: spdif@0x1011e000 {
+       compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif";
+       reg = <0x1011e000 0x2000>;
+       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+       dmas = <&dmac1_s 8>;
+       dma-names = "tx";
+       clock-names = "hclk", "mclk";
+       clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>;
+       status = "disabled";
+       #sound-dai-cells = <0>;
+};
index bac4d9ac1edc8c45df26134e59c9537b1ce6b3af..9e62f6eb348f9499923dbcb473dad6ff22678bfa 100644 (file)
@@ -14,7 +14,8 @@ Optional properties:
 
 - realtek,in1-differential
 - realtek,in2-differential
-  Boolean. Indicate MIC1/2 input are differential, rather than single-ended.
+- realtek,in3-differential
+  Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended.
 
 - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
 
@@ -24,9 +25,11 @@ Pins on the device (for linking into audio routes) for RT5639/RT5640:
   * DMIC2
   * MICBIAS1
   * IN1P
-  * IN1R
+  * IN1N
   * IN2P
-  * IN2R
+  * IN2N
+  * IN3P
+  * IN3N
   * HPOL
   * HPOR
   * LOUTL
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
new file mode 100644 (file)
index 0000000..c92966b
--- /dev/null
@@ -0,0 +1,27 @@
+* Allwinner A10 Codec
+
+Required properties:
+- compatible: must be either "allwinner,sun4i-a10-codec" or
+  "allwinner,sun7i-a20-codec"
+- reg: must contain the registers location and length
+- interrupts: must contain the codec interrupt
+- dmas: DMA channels for tx and rx dma. See the DMA client binding,
+       Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: should include "tx" and "rx".
+- clocks: a list of phandle + clock-specifer pairs, one for each entry
+  in clock-names.
+- clock-names: should contain followings:
+   - "apb": the parent APB clock for this controller
+   - "codec": the parent module clock
+
+Example:
+codec: codec@01c22c00 {
+       #sound-dai-cells = <0>;
+       compatible = "allwinner,sun7i-a20-codec";
+       reg = <0x01c22c00 0x40>;
+       interrupts = <0 30 4>;
+       clocks = <&apb0_gates 0>, <&codec_clk>;
+       clock-names = "apb", "codec";
+       dmas = <&dma 0 19>, <&dma 0 19>;
+       dma-names = "rx", "tx";
+};
index 6a2c84247f91520a4e7bd2fc90e232e8a9e6cb05..34cf70e2cbc4720510cf03e05eba6f3bcb6b2cae 100644 (file)
@@ -4,11 +4,15 @@ This specifies audio DAI's TDM slot.
 
 TDM slot properties:
 dai-tdm-slot-num : Number of slots in use.
-dai-tdm-slot-width :  Width in bits for each slot.
+dai-tdm-slot-width : Width in bits for each slot.
+dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
+dai-tdm-slot-rx-mask : Receive direction slot mask, optional
 
 For instance:
        dai-tdm-slot-num = <2>;
        dai-tdm-slot-width = <8>;
+       dai-tdm-slot-tx-mask = <0 1>;
+       dai-tdm-slot-rx-mask = <1 0>;
 
 And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
 to specify a explicit mapping of the channels and the slots. If it's absent
@@ -18,3 +22,8 @@ tx and rx masks.
 For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
 for an active slot as default, and the default active bits are at the LSB of
 the masks.
+
+The explicit masks are given as array of integers, where the first
+number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
+number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
+does not do anything, if either mask is set non zero value.
diff --git a/Documentation/devicetree/bindings/usb/keystone-phy.txt b/Documentation/devicetree/bindings/usb/keystone-phy.txt
deleted file mode 100644 (file)
index f37b3a8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-TI Keystone USB PHY
-
-Required properties:
- - compatible: should be "ti,keystone-usbphy".
- - #address-cells, #size-cells : should be '1' if the device has sub-nodes
-   with 'reg' property.
- - reg : Address and length of the usb phy control register set.
-
-The main purpose of this PHY driver is to enable the USB PHY reference clock
-gate on the Keystone SOC for both the USB2 and USB3 PHY. Otherwise it is just
-an NOP PHY driver.  Hence this node is referenced as both the usb2 and usb3
-phy node in the USB Glue layer driver node.
-
-usb_phy: usb_phy@2620738 {
-       compatible = "ti,keystone-usbphy";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       reg = <0x2620738 32>;
-       status = "disabled";
-};
diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt
deleted file mode 100644 (file)
index 379b84a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Freescale MXS USB Phy Device
-
-Required properties:
-- compatible: should contain:
-       * "fsl,imx23-usbphy" for imx23 and imx28
-       * "fsl,imx6q-usbphy" for imx6dq and imx6dl
-       * "fsl,imx6sl-usbphy" for imx6sl
-       * "fsl,vf610-usbphy" for Vybrid vf610
-       * "fsl,imx6sx-usbphy" for imx6sx
-  "fsl,imx23-usbphy" is still a fallback for other strings
-- reg: Should contain registers location and length
-- interrupts: Should contain phy interrupt
-- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
-
-Example:
-usbphy1: usbphy@020c9000 {
-       compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
-       reg = <0x020c9000 0x1000>;
-       interrupts = <0 44 0x04>;
-       fsl,anatop = <&anatop>;
-};
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
deleted file mode 100644 (file)
index a9aa79f..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-Tegra SOC USB PHY
-
-The device node for Tegra SOC USB PHY:
-
-Required properties :
- - compatible : For Tegra20, must contain "nvidia,tegra20-usb-phy".
-   For Tegra30, must contain "nvidia,tegra30-usb-phy".  Otherwise, must contain
-   "nvidia,<chip>-usb-phy" plus at least one of the above, where <chip> is
-   tegra114, tegra124, tegra132, or tegra210.
- - reg : Defines the following set of registers, in the order listed:
-   - The PHY's own register set.
-     Always present.
-   - The register set of the PHY containing the UTMI pad control registers.
-     Present if-and-only-if phy_type == utmi.
- - phy_type : Should be one of "utmi", "ulpi" or "hsic".
- - clocks : Defines the clocks listed in the clock-names property.
- - clock-names : The following clock names must be present:
-   - reg: The clock needed to access the PHY's own registers. This is the
-     associated EHCI controller's clock. Always present.
-   - pll_u: PLL_U. Always present.
-   - timer: The timeout clock (clk_m). Present if phy_type == utmi.
-   - utmi-pads: The clock needed to access the UTMI pad control registers.
-     Present if phy_type == utmi.
-   - ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2).
-     Present if phy_type == ulpi, and ULPI link mode is in use.
- - resets : Must contain an entry for each entry in reset-names.
-   See ../reset/reset.txt for details.
- - reset-names : Must include the following entries:
-   - usb: The PHY's own reset signal.
-   - utmi-pads: The reset of the PHY containing the chip-wide UTMI pad control
-     registers. Required even if phy_type == ulpi.
-
-Required properties for phy_type == ulpi:
-  - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
-
-Required PHY timing params for utmi phy, for all chips:
-  - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
-    start of sync launches RxActive
-  - nvidia,elastic-limit : Variable FIFO Depth of elastic input store
-  - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
-    before declare IDLE.
-  - nvidia,term-range-adj : Range adjusment on terminations
-  - Either one of the following for HS driver output control:
-    - nvidia,xcvr-setup : integer, uses the provided value.
-    - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read
-      from the on-chip fuses
-    If both are provided, nvidia,xcvr-setup-use-fuses takes precedence.
-  - nvidia,xcvr-lsfslew : LS falling slew rate control.
-  - nvidia,xcvr-lsrslew :  LS rising slew rate control.
-
-Required PHY timing params for utmi phy, only on Tegra30 and above:
-  - nvidia,xcvr-hsslew : HS slew rate control.
-  - nvidia,hssquelch-level : HS squelch detector level.
-  - nvidia,hsdiscon-level : HS disconnect detector level.
-
-Optional properties:
-  - nvidia,has-legacy-mode : boolean indicates whether this controller can
-    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
-    registers are accessed through the APB_MISC base address instead of
-    the USB controller.
-  - nvidia,is-wired : boolean. Indicates whether we can do certain kind of power
-    optimizations for the devices that are always connected. e.g. modem.
-  - dr_mode : dual role mode. Indicates the working mode for the PHY. Can be
-    "host", "peripheral", or "otg". Defaults to "host" if not defined.
-      host means this is a host controller
-      peripheral means it is device controller
-      otg means it can operate as either ("on the go")
-  - nvidia,has-utmi-pad-registers : boolean indicates whether this controller
-    contains the UTMI pad control registers common to all USB controllers.
-
-VBUS control (required for dr_mode == otg, optional for dr_mode == host):
-  - vbus-supply: regulator for VBUS
diff --git a/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt
deleted file mode 100644 (file)
index 2cb2168..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-Qualcomm's APQ8016/MSM8916 USB transceiver controller
-
-- compatible:
-    Usage: required
-    Value type: <string>
-    Definition: Should contain "qcom,usb-8x16-phy".
-
-- reg:
-    Usage: required
-    Value type: <prop-encoded-array>
-    Definition: USB PHY base address and length of the register map
-
-- clocks:
-    Usage: required
-    Value type: <prop-encoded-array>
-    Definition: See clock-bindings.txt section "consumers". List of
-                two clock specifiers for interface and core controller
-                clocks.
-
-- clock-names:
-    Usage: required
-    Value type: <string>
-    Definition: Must contain "iface" and "core" strings.
-
-- vddcx-supply:
-    Usage: required
-    Value type: <phandle>
-    Definition: phandle to the regulator VDCCX supply node.
-
-- v1p8-supply:
-    Usage: required
-    Value type: <phandle>
-    Definition: phandle to the regulator 1.8V supply node.
-
-- v3p3-supply:
-    Usage: required
-    Value type: <phandle>
-    Definition: phandle to the regulator 3.3V supply node.
-
-- resets:
-    Usage: required
-    Value type: <prop-encoded-array>
-    Definition: See reset.txt section "consumers". PHY reset specifier.
-
-- reset-names:
-    Usage: required
-    Value type: <string>
-    Definition: Must contain "phy" string.
-
-- switch-gpio:
-    Usage: optional
-    Value type: <prop-encoded-array>
-    Definition: Some boards are using Dual SPDT USB Switch, witch is
-                controlled by GPIO to de/multiplex D+/D- USB lines
-                between connectors.
-
-Example:
-       usb_phy: phy@78d9000 {
-               compatible = "qcom,usb-8x16-phy";
-               reg = <0x78d9000 0x400>;
-
-               vddcx-supply = <&pm8916_s1_corner>;
-               v1p8-supply = <&pm8916_l7>;
-               v3p3-supply = <&pm8916_l13>;
-
-               clocks = <&gcc GCC_USB_HS_AHB_CLK>,
-                            <&gcc GCC_USB_HS_SYSTEM_CLK>;
-               clock-names = "iface", "core";
-
-               resets = <&gcc GCC_USB2A_PHY_BCR>;
-               reset-names = "phy";
-
-               // D+/D- lines: 1 - Routed to HUB, 0 - Device connector
-               switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>;
-       };
-
diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
deleted file mode 100644 (file)
index 33fd354..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-SAMSUNG USB-PHY controllers
-
-** Samsung's usb 2.0 phy transceiver
-
-The Samsung's usb 2.0 phy transceiver is used for controlling
-usb 2.0 phy for s3c-hsotg as well as ehci-s5p and ohci-exynos
-usb controllers across Samsung SOCs.
-TODO: Adding the PHY binding with controller(s) according to the under
-development generic PHY driver.
-
-Required properties:
-
-Exynos4210:
-- compatible : should be "samsung,exynos4210-usb2phy"
-- reg : base physical address of the phy registers and length of memory mapped
-       region.
-- clocks: Clock IDs array as required by the controller.
-- clock-names: names of clock correseponding IDs clock property as requested
-              by the controller driver.
-
-Exynos5250:
-- compatible : should be "samsung,exynos5250-usb2phy"
-- reg : base physical address of the phy registers and length of memory mapped
-       region.
-
-Optional properties:
-- #address-cells: should be '1' when usbphy node has a child node with 'reg'
-                 property.
-- #size-cells: should be '1' when usbphy node has a child node with 'reg'
-              property.
-- ranges: allows valid translation between child's address space and parent's
-         address space.
-
-- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
-  interface for usb-phy. It should provide the following information required by
-  usb-phy controller to control phy.
-  - reg : base physical address of PHY_CONTROL registers.
-         The size of this register is the total sum of size of all PHY_CONTROL
-         registers that the SoC has. For example, the size will be
-         '0x4' in case we have only one PHY_CONTROL register (e.g.
-         OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
-         and, '0x8' in case we have two PHY_CONTROL registers (e.g.
-         USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
-         and so on.
-
-Example:
- - Exynos4210
-
-       usbphy@125B0000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "samsung,exynos4210-usb2phy";
-               reg = <0x125B0000 0x100>;
-               ranges;
-
-               clocks = <&clock 2>, <&clock 305>;
-               clock-names = "xusbxti", "otg";
-
-               usbphy-sys {
-                       /* USB device and host PHY_CONTROL registers */
-                       reg = <0x10020704 0x8>;
-               };
-       };
-
-
-** Samsung's usb 3.0 phy transceiver
-
-Starting exynso5250, Samsung's SoC have usb 3.0 phy transceiver
-which is used for controlling usb 3.0 phy for dwc3-exynos usb 3.0
-controllers across Samsung SOCs.
-
-Required properties:
-
-Exynos5250:
-- compatible : should be "samsung,exynos5250-usb3phy"
-- reg : base physical address of the phy registers and length of memory mapped
-       region.
-- clocks: Clock IDs array as required by the controller.
-- clock-names: names of clocks correseponding to IDs in the clock property
-              as requested by the controller driver.
-
-Optional properties:
-- #address-cells: should be '1' when usbphy node has a child node with 'reg'
-                 property.
-- #size-cells: should be '1' when usbphy node has a child node with 'reg'
-              property.
-- ranges: allows valid translation between child's address space and parent's
-         address space.
-
-- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
-  interface for usb-phy. It should provide the following information required by
-  usb-phy controller to control phy.
-  - reg : base physical address of PHY_CONTROL registers.
-         The size of this register is the total sum of size of all PHY_CONTROL
-         registers that the SoC has. For example, the size will be
-         '0x4' in case we have only one PHY_CONTROL register (e.g.
-         OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
-         and, '0x8' in case we have two PHY_CONTROL registers (e.g.
-         USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
-         and so on.
-
-Example:
-       usbphy@12100000 {
-               compatible = "samsung,exynos5250-usb3phy";
-               reg = <0x12100000 0x100>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               clocks = <&clock 1>, <&clock 286>;
-               clock-names = "ext_xtal", "usbdrd30";
-
-               usbphy-sys {
-                       /* USB device and host PHY_CONTROL registers */
-                       reg = <0x10040704 0x8>;
-               };
-       };
index 13e54a0e78b9b50878226a479693d3f37863ea16..8c6cef73e0d7c4f9e597e060151dff255a429044 100644 (file)
@@ -51,6 +51,7 @@ cirrus        Cirrus Logic, Inc.
 cloudengines   Cloud Engines, Inc.
 cnm    Chips&Media, Inc.
 cnxt   Conexant Systems, Inc.
+compulab       CompuLab Ltd.
 cortina        Cortina Systems, Inc.
 cosmic Cosmic Circuits
 crystalfontz   Crystalfontz America, Inc.
@@ -82,6 +83,7 @@ everspin      Everspin Technologies, Inc.
 excito Excito
 fcs    Fairchild Semiconductor
 firefly        Firefly
+focaltech      FocalTech Systems Co.,Ltd
 fsl    Freescale Semiconductor
 GEFanuc        GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 gef    GE Fanuc Intelligent Platforms Embedded Systems, Inc.
@@ -195,6 +197,7 @@ seagate     Seagate Technology PLC
 semtech        Semtech Corporation
 sgx    SGX Sensortech
 sharp  Sharp Corporation
+sigma  Sigma Designs, Inc.
 sil    Silicon Image
 silabs Silicon Laboratories
 siliconmitus   Silicon Mitus, Inc.
diff --git a/Documentation/devicetree/bindings/video/adi,adv7123.txt b/Documentation/devicetree/bindings/video/adi,adv7123.txt
deleted file mode 100644 (file)
index a6b2b2b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-Analog Device ADV7123 Video DAC
--------------------------------
-
-The ADV7123 is a digital-to-analog converter that outputs VGA signals from a
-parallel video input.
-
-Required properties:
-
-- compatible: Should be "adi,adv7123"
-
-Optional properties:
-
-- psave-gpios: Power save control GPIO
-
-Required nodes:
-
-The ADV7123 has two video ports. Their connections are modeled using the OF
-graph bindings specified in Documentation/devicetree/bindings/graph.txt.
-
-- Video port 0 for DPI input
-- Video port 1 for VGA output
-
-
-Example
--------
-
-       adv7123: encoder@0 {
-               compatible = "adi,adv7123";
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-
-                               adv7123_in: endpoint@0 {
-                                       remote-endpoint = <&dpi_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-
-                               adv7123_out: endpoint@0 {
-                                       remote-endpoint = <&vga_connector_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/adi,adv7511.txt b/Documentation/devicetree/bindings/video/adi,adv7511.txt
deleted file mode 100644 (file)
index 96c25ee..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-Analog Device ADV7511(W)/13 HDMI Encoders
------------------------------------------
-
-The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
-compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
-S/PDIF, CEC and HDCP.
-
-Required properties:
-
-- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
-- reg: I2C slave address
-
-The ADV7511 supports a large number of input data formats that differ by their
-color depth, color format, clock mode, bit justification and random
-arrangement of components on the data bus. The combination of the following
-properties describe the input and map directly to the video input tables of the
-ADV7511 datasheet that document all the supported combinations.
-
-- adi,input-depth: Number of bits per color component at the input (8, 10 or
-  12).
-- adi,input-colorspace: The input color space, one of "rgb", "yuv422" or
-  "yuv444".
-- adi,input-clock: The input clock type, one of "1x" (one clock cycle per
-  pixel), "2x" (two clock cycles per pixel), "ddr" (one clock cycle per pixel,
-  data driven on both edges).
-
-The following input format properties are required except in "rgb 1x" and
-"yuv444 1x" modes, in which case they must not be specified.
-
-- adi,input-style: The input components arrangement variant (1, 2 or 3), as
-  listed in the input format tables in the datasheet.
-- adi,input-justification: The input bit justification ("left", "evenly",
-  "right").
-
-Optional properties:
-
-- interrupts: Specifier for the ADV7511 interrupt
-- pd-gpios: Specifier for the GPIO connected to the power down signal
-
-- adi,clock-delay: Video data clock delay relative to the pixel clock, in ps
-  (-1200 ps .. 1600 ps). Defaults to no delay.
-- adi,embedded-sync: The input uses synchronization signals embedded in the
-  data stream (similar to BT.656). Defaults to separate H/V synchronization
-  signals.
-
-Required nodes:
-
-The ADV7511 has two video ports. Their connections are modelled using the OF
-graph bindings specified in Documentation/devicetree/bindings/graph.txt.
-
-- Video port 0 for the RGB or YUV input
-- Video port 1 for the HDMI output
-
-
-Example
--------
-
-       adv7511w: hdmi@39 {
-               compatible = "adi,adv7511w";
-               reg = <39>;
-               interrupt-parent = <&gpio3>;
-               interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
-
-               adi,input-depth = <8>;
-               adi,input-colorspace = "rgb";
-               adi,input-clock = "1x";
-               adi,input-style = <1>;
-               adi,input-justification = "evenly";
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-                               adv7511w_in: endpoint {
-                                       remote-endpoint = <&dpi_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-                               adv7511_out: endpoint {
-                                       remote-endpoint = <&hdmi_connector_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/analog-tv-connector.txt b/Documentation/devicetree/bindings/video/analog-tv-connector.txt
deleted file mode 100644 (file)
index 0c0970c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Analog TV Connector
-===================
-
-Required properties:
-- compatible: "composite-video-connector" or "svideo-connector"
-
-Optional properties:
-- label: a symbolic name for the connector
-
-Required nodes:
-- Video port for TV input
-
-Example
--------
-
-tv: connector {
-       compatible = "composite-video-connector";
-       label = "tv";
-
-       port {
-               tv_connector_in: endpoint {
-                       remote-endpoint = <&venc_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/arm,pl11x.txt b/Documentation/devicetree/bindings/video/arm,pl11x.txt
deleted file mode 100644 (file)
index 3e3039a..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-* ARM PrimeCell Color LCD Controller PL110/PL111
-
-See also Documentation/devicetree/bindings/arm/primecell.txt
-
-Required properties:
-
-- compatible: must be one of:
-       "arm,pl110", "arm,primecell"
-       "arm,pl111", "arm,primecell"
-
-- reg: base address and size of the control registers block
-
-- interrupt-names: either the single entry "combined" representing a
-       combined interrupt output (CLCDINTR), or the four entries
-       "mbe", "vcomp", "lnbu", "fuf" representing the individual
-       CLCDMBEINTR, CLCDVCOMPINTR, CLCDLNBUINTR, CLCDFUFINTR interrupts
-
-- interrupts: contains an interrupt specifier for each entry in
-       interrupt-names
-
-- clock-names: should contain "clcdclk" and "apb_pclk"
-
-- clocks: contains phandle and clock specifier pairs for the entries
-       in the clock-names property. See
-       Documentation/devicetree/binding/clock/clock-bindings.txt
-
-Optional properties:
-
-- memory-region: phandle to a node describing memory (see
-       Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
-       to be used for the framebuffer; if not present, the framebuffer
-       may be located anywhere in the memory
-
-- max-memory-bandwidth: maximum bandwidth in bytes per second that the
-       cell's memory interface can handle; if not present, the memory
-       interface is fast enough to handle all possible video modes
-
-Required sub-nodes:
-
-- port: describes LCD panel signals, following the common binding
-       for video transmitter interfaces; see
-       Documentation/devicetree/bindings/media/video-interfaces.txt;
-       when it is a TFT panel, the port's endpoint must define the
-       following property:
-
-       - arm,pl11x,tft-r0g0b0-pads: an array of three 32-bit values,
-               defining the way CLD pads are wired up; first value
-               contains index of the "CLD" external pin (pad) used
-               as R0 (first bit of the red component), second value
-               index of the pad used as G0, third value index of the
-               pad used as B0, see also "LCD panel signal multiplexing
-               details" paragraphs in the PL110/PL111 Technical
-               Reference Manuals; this implicitly defines available
-               color modes, for example:
-               - PL111 TFT 4:4:4 panel:
-                       arm,pl11x,tft-r0g0b0-pads = <4 15 20>;
-               - PL110 TFT (1:)5:5:5 panel:
-                       arm,pl11x,tft-r0g0b0-pads = <1 7 13>;
-               - PL111 TFT (1:)5:5:5 panel:
-                       arm,pl11x,tft-r0g0b0-pads = <3 11 19>;
-               - PL111 TFT 5:6:5 panel:
-                       arm,pl11x,tft-r0g0b0-pads = <3 10 19>;
-               - PL110 and PL111 TFT 8:8:8 panel:
-                       arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
-               - PL110 and PL111 TFT 8:8:8 panel, R & B components swapped:
-                       arm,pl11x,tft-r0g0b0-pads = <16 8 0>;
-
-
-Example:
-
-       clcd@10020000 {
-               compatible = "arm,pl111", "arm,primecell";
-               reg = <0x10020000 0x1000>;
-               interrupt-names = "combined";
-               interrupts = <0 44 4>;
-               clocks = <&oscclk1>, <&oscclk2>;
-               clock-names = "clcdclk", "apb_pclk";
-               max-memory-bandwidth = <94371840>; /* Bps, 1024x768@60 16bpp */
-
-               port {
-                       clcd_pads: endpoint {
-                               remote-endpoint = <&clcd_panel>;
-                               arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
-                       };
-               };
-
-       };
-
-       panel {
-               compatible = "panel-dpi";
-
-               port {
-                       clcd_panel: endpoint {
-                               remote-endpoint = <&clcd_pads>;
-                       };
-               };
-
-               panel-timing {
-                       clock-frequency = <25175000>;
-                       hactive = <640>;
-                       hback-porch = <40>;
-                       hfront-porch = <24>;
-                       hsync-len = <96>;
-                       vactive = <480>;
-                       vback-porch = <32>;
-                       vfront-porch = <11>;
-                       vsync-len = <2>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/atmel,lcdc.txt b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
deleted file mode 100644 (file)
index ecb8da0..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-Atmel LCDC Framebuffer
------------------------------------------------------
-
-Required properties:
-- compatible :
-       "atmel,at91sam9261-lcdc" , 
-       "atmel,at91sam9263-lcdc" ,
-       "atmel,at91sam9g10-lcdc" ,
-       "atmel,at91sam9g45-lcdc" ,
-       "atmel,at91sam9g45es-lcdc" ,
-       "atmel,at91sam9rl-lcdc" ,
-       "atmel,at32ap-lcdc"
-- reg : Should contain 1 register ranges(address and length).
-       Can contain an additional register range(address and length)
-       for fixed framebuffer memory. Useful for dedicated memories.
-- interrupts : framebuffer controller interrupt
-- display: a phandle pointing to the display node
-
-Required nodes:
-- display: a display node is required to initialize the lcd panel
-       This should be in the board dts.
-- default-mode: a videomode within the display with timing parameters
-       as specified below.
-
-Optional properties:
-- lcd-supply: Regulator for LCD supply voltage.
-
-Example:
-
-       fb0: fb@0x00500000 {
-               compatible = "atmel,at91sam9g45-lcdc";
-               reg = <0x00500000 0x1000>;
-               interrupts = <23 3 0>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_fb>;
-               display = <&display0>;
-               status = "okay";
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-       };
-
-Example for fixed framebuffer memory:
-
-       fb0: fb@0x00500000 {
-               compatible = "atmel,at91sam9263-lcdc";
-               reg = <0x00700000 0x1000 0x70000000 0x200000>;
-               [...]
-       };
-
-Atmel LCDC Display
------------------------------------------------------
-Required properties (as per of_videomode_helper):
-
- - atmel,dmacon: dma controller configuration
- - atmel,lcdcon2: lcd controller configuration
- - atmel,guard-time: lcd guard time (Delay in frame periods)
- - bits-per-pixel: lcd panel bit-depth.
-
-Optional properties (as per of_videomode_helper):
- - atmel,lcdcon-backlight: enable backlight
- - atmel,lcdcon-backlight-inverted: invert backlight PWM polarity
- - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"
- - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
-
-Example:
-       display0: display {
-               bits-per-pixel = <32>;
-               atmel,lcdcon-backlight;
-               atmel,dmacon = <0x1>;
-               atmel,lcdcon2 = <0x80008002>;
-               atmel,guard-time = <9>;
-               atmel,lcd-wiring-mode = <1>;
-
-               display-timings {
-                       native-mode = <&timing0>;
-                       timing0: timing0 {
-                               clock-frequency = <9000000>;
-                               hactive = <480>;
-                               vactive = <272>;
-                               hback-porch = <1>;
-                               hfront-porch = <1>;
-                               vback-porch = <40>;
-                               vfront-porch = <1>;
-                               hsync-len = <45>;
-                               vsync-len = <1>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/88pm860x.txt b/Documentation/devicetree/bindings/video/backlight/88pm860x.txt
deleted file mode 100644 (file)
index 261df27..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-88pm860x-backlight bindings
-
-Optional properties:
-  - marvell,88pm860x-iset: Current supplies on backlight device.
-  - marvell,88pm860x-pwm: PWM frequency on backlight device.
-
-Example:
-
-       backlights {
-               backlight-0 {
-                       marvell,88pm860x-iset = <4>;
-                       marvell,88pm860x-pwm = <3>;
-               };
-               backlight-2 {
-               };
diff --git a/Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt b/Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt
deleted file mode 100644 (file)
index 321be66..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-gpio-backlight bindings
-
-Required properties:
-  - compatible: "gpio-backlight"
-  - gpios: describes the gpio that is used for enabling/disabling the backlight.
-    refer to bindings/gpio/gpio.txt for more details.
-
-Optional properties:
-  - default-on: enable the backlight at boot.
-
-Example:
-       backlight {
-               compatible = "gpio-backlight";
-               gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
-               default-on;
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
deleted file mode 100644 (file)
index 0a3ecbc..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-lp855x bindings
-
-Required properties:
-  - compatible: "ti,lp8550", "ti,lp8551", "ti,lp8552", "ti,lp8553",
-                "ti,lp8555", "ti,lp8556", "ti,lp8557"
-  - reg: I2C slave address (u8)
-  - dev-ctrl: Value of DEVICE CONTROL register (u8). It depends on the device.
-
-Optional properties:
-  - bl-name: Backlight device name (string)
-  - init-brt: Initial value of backlight brightness (u8)
-  - pwm-period: PWM period value. Set only PWM input mode used (u32)
-  - rom-addr: Register address of ROM area to be updated (u8)
-  - rom-val: Register value to be updated (u8)
-  - power-supply: Regulator which controls the 3V rail
-
-Example:
-
-       /* LP8555 */
-       backlight@2c {
-               compatible = "ti,lp8555";
-               reg = <0x2c>;
-
-               dev-ctrl = /bits/ 8 <0x00>;
-               pwm-period = <10000>;
-
-               /* 4V OV, 4 output LED0 string enabled */
-               rom_14h {
-                       rom-addr = /bits/ 8 <0x14>;
-                       rom-val = /bits/ 8 <0xcf>;
-               };
-
-               /* Heavy smoothing, 24ms ramp time step */
-               rom_15h {
-                       rom-addr = /bits/ 8 <0x15>;
-                       rom-val = /bits/ 8 <0xc7>;
-               };
-
-               /* 4 output LED1 string enabled */
-               rom_19h {
-                       rom-addr = /bits/ 8 <0x19>;
-                       rom-val = /bits/ 8 <0x0f>;
-               };
-       };
-
-       /* LP8556 */
-       backlight@2c {
-               compatible = "ti,lp8556";
-               reg = <0x2c>;
-
-               bl-name = "lcd-bl";
-               dev-ctrl = /bits/ 8 <0x85>;
-               init-brt = /bits/ 8 <0x10>;
-       };
-
-       /* LP8557 */
-       backlight@2c {
-               compatible = "ti,lp8557";
-               reg = <0x2c>;
-               power-supply = <&backlight_vdd>;
-
-               dev-ctrl = /bits/ 8 <0x41>;
-               init-brt = /bits/ 8 <0x0a>;
-
-               /* 4V OV, 4 output LED string enabled */
-               rom_14h {
-                       rom-addr = /bits/ 8 <0x14>;
-                       rom-val = /bits/ 8 <0xcf>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt b/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt
deleted file mode 100644 (file)
index b4cffda..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-88pm860x-backlight bindings
-
-Optional properties:
-  - maxim,max8925-dual-string: whether support dual string
-
-Example:
-
-       backlights {
-               maxim,max8925-dual-string = <0>;
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt b/Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt
deleted file mode 100644 (file)
index e5b294d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Binding for Qualcomm PM8941 WLED driver
-
-Required properties:
-- compatible: should be "qcom,pm8941-wled"
-- reg: slave address
-
-Optional properties:
-- default-brightness: brightness value on boot, value from: 0-4095
-       default: 2048
-- label: The name of the backlight device
-- qcom,cs-out: bool; enable current sink output
-- qcom,cabc: bool; enable content adaptive backlight control
-- qcom,ext-gen: bool; use externally generated modulator signal to dim
-- qcom,current-limit: mA; per-string current limit; value from 0 to 25
-       default: 20mA
-- qcom,current-boost-limit: mA; boost current limit; one of:
-       105, 385, 525, 805, 980, 1260, 1400, 1680
-       default: 805mA
-- qcom,switching-freq: kHz; switching frequency; one of:
-       600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
-       1600, 1920, 2400, 3200, 4800, 9600,
-       default: 1600kHz
-- qcom,ovp: V; Over-voltage protection limit; one of:
-       27, 29, 32, 35
-       default: 29V
-- qcom,num-strings: #; number of led strings attached; value from 1 to 3
-       default: 2
-
-Example:
-
-pm8941-wled@d800 {
-       compatible = "qcom,pm8941-wled";
-       reg = <0xd800>;
-       label = "backlight";
-
-       qcom,cs-out;
-       qcom,current-limit = <20>;
-       qcom,current-boost-limit = <805>;
-       qcom,switching-freq = <1600>;
-       qcom,ovp = <29>;
-       qcom,num-strings = <2>;
-};
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
deleted file mode 100644 (file)
index 764db86..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-pwm-backlight bindings
-
-Required properties:
-  - compatible: "pwm-backlight"
-  - pwms: OF device-tree PWM specification (see PWM binding[0])
-  - brightness-levels: Array of distinct brightness levels. Typically these
-      are in the range from 0 to 255, but any range starting at 0 will do.
-      The actual brightness level (PWM duty cycle) will be interpolated
-      from these values. 0 means a 0% duty cycle (darkest/off), while the
-      last value in the array represents a 100% duty cycle (brightest).
-  - default-brightness-level: the default brightness level (index into the
-      array defined by the "brightness-levels" property)
-  - power-supply: regulator for supply voltage
-
-Optional properties:
-  - pwm-names: a list of names for the PWM devices specified in the
-               "pwms" property (see PWM binding[0])
-  - enable-gpios: contains a single GPIO specifier for the GPIO which enables
-                  and disables the backlight (see GPIO binding[1])
-
-[0]: Documentation/devicetree/bindings/pwm/pwm.txt
-[1]: Documentation/devicetree/bindings/gpio/gpio.txt
-
-Example:
-
-       backlight {
-               compatible = "pwm-backlight";
-               pwms = <&pwm 0 5000000>;
-
-               brightness-levels = <0 4 8 16 32 64 128 255>;
-               default-brightness-level = <6>;
-
-               power-supply = <&vdd_bl_reg>;
-               enable-gpios = <&gpio 58 0>;
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt b/Documentation/devicetree/bindings/video/backlight/sky81452-backlight.txt
deleted file mode 100644 (file)
index 8bf2940..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-SKY81452-backlight bindings
-
-Required properties:
-- compatible           : Must be "skyworks,sky81452-backlight"
-
-Optional properties:
-- name                 : Name of backlight device. Default is 'lcd-backlight'.
-- gpios                        : GPIO to use to EN pin.
-                       See Documentation/devicetree/bindings/gpio/gpio.txt
-- led-sources          : List of enabled channels from 0 to 5.
-                       See Documentation/devicetree/bindings/leds/common.txt
-- skyworks,ignore-pwm  : Ignore both PWM input
-- skyworks,dpwm-mode   : Enable DPWM dimming mode, otherwise Analog dimming.
-- skyworks,phase-shift : Enable phase shift mode
-- skyworks,short-detection-threshold-volt
-                       : It should be one of 4, 5, 6 and 7V.
-- skyworks,current-limit-mA
-                       : It should be 2300mA or 2750mA.
-
-Example:
-
-       backlight {
-               compatible = "skyworks,sky81452-backlight";
-               name = "pwm-backlight";
-               led-sources = <0 1 2 5>;
-               skyworks,ignore-pwm;
-               skyworks,phase-shift;
-               skyworks,current-limit-mA = <2300>;
-       };
diff --git a/Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt b/Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt
deleted file mode 100644 (file)
index 5fb9279..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-TPS65217 family of regulators
-
-The TPS65217 chip contains a boost converter and current sinks which can be
-used to drive LEDs for use as backlights.
-
-Required properties:
-- compatible: "ti,tps65217"
-- reg: I2C slave address
-- backlight: node for specifying WLED1 and WLED2 lines in TPS65217
-- isel: selection bit, valid values: 1 for ISEL1 (low-level) and 2 for ISEL2 (high-level)
-- fdim: PWM dimming frequency, valid values: 100, 200, 500, 1000
-- default-brightness: valid values: 0-100
-
-Each regulator is defined using the standard binding for regulators.
-
-Example:
-
-       tps: tps@24 {
-               reg = <0x24>;
-               compatible = "ti,tps65217";
-               backlight {
-                       isel = <1>;  /* 1 - ISET1, 2 ISET2 */
-                       fdim = <100>; /* TPS65217_BL_FDIM_100HZ */
-                       default-brightness = <50>;
-               };
-       };
-
diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
deleted file mode 100644 (file)
index c989c38..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-ps8622-bridge bindings
-
-Required properties:
-       - compatible: "parade,ps8622" or "parade,ps8625"
-       - reg: first i2c address of the bridge
-       - sleep-gpios: OF device-tree gpio specification for PD_ pin.
-       - reset-gpios: OF device-tree gpio specification for RST_ pin.
-
-Optional properties:
-       - lane-count: number of DP lanes to use
-       - use-external-pwm: backlight will be controlled by an external PWM
-       - video interfaces: Device node can contain video interface port
-                           nodes for panel according to [1].
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-       lvds-bridge@48 {
-               compatible = "parade,ps8622";
-               reg = <0x48>;
-               sleep-gpios = <&gpc3 6 1 0 0>;
-               reset-gpios = <&gpc3 1 1 0 0>;
-               lane-count = <1>;
-               ports {
-                       port@0 {
-                               bridge_out: endpoint {
-                                       remote-endpoint = <&panel_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/bridge/ptn3460.txt b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
deleted file mode 100644 (file)
index 361971b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-ptn3460 bridge bindings
-
-Required properties:
-       - compatible: "nxp,ptn3460"
-       - reg: i2c address of the bridge
-       - powerdown-gpio: OF device-tree gpio specification  for PD_N pin.
-       - reset-gpio: OF device-tree gpio specification for RST_N pin.
-       - edid-emulation: The EDID emulation entry to use
-               +-------+------------+------------------+
-               | Value | Resolution | Description      |
-               |   0   |  1024x768  | NXP Generic      |
-               |   1   |  1920x1080 | NXP Generic      |
-               |   2   |  1920x1080 | NXP Generic      |
-               |   3   |  1600x900  | Samsung LTM200KT |
-               |   4   |  1920x1080 | Samsung LTM230HT |
-               |   5   |  1366x768  | NXP Generic      |
-               |   6   |  1600x900  | ChiMei M215HGE   |
-               +-------+------------+------------------+
-
-       - video interfaces: Device node can contain video interface port
-                           nodes for panel according to [1].
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-       lvds-bridge@20 {
-               compatible = "nxp,ptn3460";
-               reg = <0x20>;
-               powerdown-gpio = <&gpy2 5 1 0 0>;
-               reset-gpio = <&gpx1 5 1 0 0>;
-               edid-emulation = <5>;
-               ports {
-                       port@0 {
-                               bridge_out: endpoint {
-                                       remote-endpoint = <&panel_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/cirrus,clps711x-fb.txt b/Documentation/devicetree/bindings/video/cirrus,clps711x-fb.txt
deleted file mode 100644 (file)
index 6fc3c6a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-* Currus Logic CLPS711X Framebuffer
-
-Required properties:
-- compatible: Shall contain "cirrus,clps711x-fb".
-- reg       : Physical base address and length of the controller's registers +
-              location and size of the framebuffer memory.
-- clocks    : phandle + clock specifier pair of the FB reference clock.
-- display   : phandle to a display node as described in
-              Documentation/devicetree/bindings/video/display-timing.txt.
-              Additionally, the display node has to define properties:
-  - bits-per-pixel: Bits per pixel.
-  - ac-prescale   : LCD AC bias frequency. This frequency is the required
-                    AC bias frequency for a given manufacturer's LCD plate.
-  - cmap-invert   : Invert the color levels (Optional).
-
-Optional properties:
-- lcd-supply: Regulator for LCD supply voltage.
-
-Example:
-       fb: fb@800002c0 {
-               compatible = "cirrus,ep7312-fb", "cirrus,clps711x-fb";
-               reg = <0x800002c0 0xd44>, <0x60000000 0xc000>;
-               clocks = <&clks 2>;
-               lcd-supply = <&reg5v0>;
-               display = <&display>;
-       };
-
-       display: display {
-               model = "320x240x4";
-               native-mode = <&timing0>;
-               bits-per-pixel = <4>;
-               ac-prescale = <17>;
-
-               display-timings {
-                       timing0: 320x240 {
-                               hactive = <320>;
-                               hback-porch = <0>;
-                               hfront-porch = <0>;
-                               hsync-len = <0>;
-                               vactive = <240>;
-                               vback-porch = <0>;
-                               vfront-porch = <0>;
-                               vsync-len = <0>;
-                               clock-frequency = <6500000>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/display-timing.txt b/Documentation/devicetree/bindings/video/display-timing.txt
deleted file mode 100644 (file)
index e1d4a0b..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-display-timing bindings
-=======================
-
-display-timings node
---------------------
-
-required properties:
- - none
-
-optional properties:
- - native-mode: The native mode for the display, in case multiple modes are
-               provided. When omitted, assume the first node is the native.
-
-timing subnode
---------------
-
-required properties:
- - hactive, vactive: display resolution
- - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters
-   in pixels
-   vfront-porch, vback-porch, vsync-len: vertical display timing parameters in
-   lines
- - clock-frequency: display clock in Hz
-
-optional properties:
- - hsync-active: hsync pulse is active low/high/ignored
- - vsync-active: vsync pulse is active low/high/ignored
- - de-active: data-enable pulse is active low/high/ignored
- - pixelclk-active: with
-                       - active high = drive pixel data on rising edge/
-                                       sample data on falling edge
-                       - active low  = drive pixel data on falling edge/
-                                       sample data on rising edge
-                       - ignored     = ignored
- - interlaced (bool): boolean to enable interlaced mode
- - doublescan (bool): boolean to enable doublescan mode
- - doubleclk (bool): boolean to enable doubleclock mode
-
-All the optional properties that are not bool follow the following logic:
-    <1>: high active
-    <0>: low active
-    omitted: not used on hardware
-
-There are different ways of describing the capabilities of a display. The
-devicetree representation corresponds to the one commonly found in datasheets
-for displays. If a display supports multiple signal timings, the native-mode
-can be specified.
-
-The parameters are defined as:
-
-  +----------+-------------------------------------+----------+-------+
-  |          |        â†‘                            |          |       |
-  |          |        |vback_porch                 |          |       |
-  |          |        â†“                            |          |       |
-  +----------#######################################----------+-------+
-  |          #        â†‘                            #          |       |
-  |          #        |                            #          |       |
-  |  hback   #        |                            #  hfront  | hsync |
-  |   porch  #        |       hactive              #  porch   |  len  |
-  |<-------->#<-------+--------------------------->#<-------->|<----->|
-  |          #        |                            #          |       |
-  |          #        |vactive                     #          |       |
-  |          #        |                            #          |       |
-  |          #        â†“                            #          |       |
-  +----------#######################################----------+-------+
-  |          |        â†‘                            |          |       |
-  |          |        |vfront_porch                |          |       |
-  |          |        â†“                            |          |       |
-  +----------+-------------------------------------+----------+-------+
-  |          |        â†‘                            |          |       |
-  |          |        |vsync_len                   |          |       |
-  |          |        â†“                            |          |       |
-  +----------+-------------------------------------+----------+-------+
-
-Example:
-
-       display-timings {
-               native-mode = <&timing0>;
-               timing0: 1080p24 {
-                       /* 1920x1080p24 */
-                       clock-frequency = <52000000>;
-                       hactive = <1920>;
-                       vactive = <1080>;
-                       hfront-porch = <25>;
-                       hback-porch = <25>;
-                       hsync-len = <25>;
-                       vback-porch = <2>;
-                       vfront-porch = <2>;
-                       vsync-len = <2>;
-                       hsync-active = <1>;
-               };
-       };
-
-Every required property also supports the use of ranges, so the commonly used
-datasheet description with minimum, typical and maximum values can be used.
-
-Example:
-
-       timing1: timing {
-               /* 1920x1080p24 */
-               clock-frequency = <148500000>;
-               hactive = <1920>;
-               vactive = <1080>;
-               hsync-len = <0 44 60>;
-               hfront-porch = <80 88 95>;
-               hback-porch = <100 148 160>;
-               vfront-porch = <0 4 6>;
-               vback-porch = <0 36 50>;
-               vsync-len = <0 5 6>;
-       };
diff --git a/Documentation/devicetree/bindings/video/dvi-connector.txt b/Documentation/devicetree/bindings/video/dvi-connector.txt
deleted file mode 100644 (file)
index fc53f7c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-DVI Connector
-==============
-
-Required properties:
-- compatible: "dvi-connector"
-
-Optional properties:
-- label: a symbolic name for the connector
-- ddc-i2c-bus: phandle to the i2c bus that is connected to DVI DDC
-- analog: the connector has DVI analog pins
-- digital: the connector has DVI digital pins
-- dual-link: the connector has pins for DVI dual-link
-
-Required nodes:
-- Video port for DVI input
-
-Note: One (or both) of 'analog' or 'digital' must be set.
-
-Example
--------
-
-dvi0: connector@0 {
-       compatible = "dvi-connector";
-       label = "dvi";
-
-       digital;
-
-       ddc-i2c-bus = <&i2c3>;
-
-       port {
-               dvi_connector_in: endpoint {
-                       remote-endpoint = <&tfp410_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
deleted file mode 100644 (file)
index 668091f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Rockchip specific extensions to the Synopsys Designware HDMI
-================================
-
-Required properties:
-- compatible: "rockchip,rk3288-dw-hdmi";
-- reg: Physical base address and length of the controller's registers.
-- clocks: phandle to hdmi iahb and isfr clocks.
-- clock-names: should be "iahb" "isfr"
-- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
-- interrupts: HDMI interrupt number
-- ports: contain a port node with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt. For
-  vopb,set the reg = <0> and set the reg = <1> for vopl.
-- reg-io-width: the width of the reg:1,4, the value should be 4 on
-  rk3288 platform
-
-Optional properties
-- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
-
-Example:
-hdmi: hdmi@ff980000 {
-       compatible = "rockchip,rk3288-dw-hdmi";
-       reg = <0xff980000 0x20000>;
-       reg-io-width = <4>;
-       ddc-i2c-bus = <&i2c5>;
-       rockchip,grf = <&grf>;
-       interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-       clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
-       clock-names = "iahb", "isfr";
-       status = "disabled";
-       ports {
-               hdmi_in: port {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       hdmi_in_vopb: endpoint@0 {
-                               reg = <0>;
-                               remote-endpoint = <&vopb_out_hdmi>;
-                       };
-                       hdmi_in_vopl: endpoint@1 {
-                               reg = <1>;
-                               remote-endpoint = <&vopl_out_hdmi>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/exynos-mic.txt b/Documentation/devicetree/bindings/video/exynos-mic.txt
deleted file mode 100644 (file)
index 0fba2ee..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-Device-Tree bindings for Samsung Exynos SoC mobile image compressor (MIC)
-
-MIC (mobile image compressor) resides between decon and mipi dsi. Mipi dsi is
-not capable to transfer high resoltuion frame data as decon can send. MIC
-solves this problem by compressing the frame data by 1/2 before it is
-transferred through mipi dsi. The compressed frame data must be uncompressed in
-the panel PCB.
-
-Required properties:
-- compatible: value should be "samsung,exynos5433-mic".
-- reg: physical base address and length of the MIC registers set and system
-       register of mic.
-- clocks: must include clock specifiers corresponding to entries in the
-         clock-names property.
-- clock-names: list of clock names sorted in the same order as the clocks
-              property. Must contain "pclk_mic0", "sclk_rgb_vclk_to_mic0".
-- samsung,disp-syscon: the reference node for syscon for DISP block.
-- ports: contains a port which is connected to decon node and dsi node.
-        address-cells and size-cells must 1 and 0, respectively.
-- port: contains an endpoint node which is connected to the endpoint in the
-       decon node or dsi node. The reg value must be 0 and 1 respectively.
-
-Example:
-SoC specific DT entry:
-mic: mic@13930000 {
-       compatible = "samsung,exynos5433-mic";
-       reg = <0x13930000 0x48>;
-       clocks = <&cmu_disp CLK_PCLK_MIC0>,
-              <&cmu_disp CLK_SCLK_RGB_VCLK_TO_MIC0>;
-       clock-names = "pclk_mic0", "sclk_rgb_vclk_to_mic0";
-       samsung,disp-syscon = <&syscon_disp>;
-
-       ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-                       mic_to_decon: endpoint {
-                               remote-endpoint = <&decon_to_mic>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-                       mic_to_dsi: endpoint {
-                               remote-endpoint = <&dsi_to_mic>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/exynos5433-decon.txt b/Documentation/devicetree/bindings/video/exynos5433-decon.txt
deleted file mode 100644 (file)
index 377afbf..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Device-Tree bindings for Samsung Exynos SoC display controller (DECON)
-
-DECON (Display and Enhancement Controller) is the Display Controller for the
-Exynos series of SoCs which transfers the image data from a video memory
-buffer to an external LCD interface.
-
-Required properties:
-- compatible: value should be "samsung,exynos5433-decon";
-- reg: physical base address and length of the DECON registers set.
-- interrupts: should contain a list of all DECON IP block interrupts in the
-             order: VSYNC, LCD_SYSTEM. The interrupt specifier format
-             depends on the interrupt controller used.
-- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys"
-                  in the same order as they were listed in the interrupts
-                  property.
-- clocks: must include clock specifiers corresponding to entries in the
-         clock-names property.
-- clock-names: list of clock names sorted in the same order as the clocks
-              property. Must contain "aclk_decon", "aclk_smmu_decon0x",
-              "aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk",
-              "sclk_decon_eclk"
-- ports: contains a port which is connected to mic node. address-cells and
-        size-cells must 1 and 0, respectively.
-- port: contains an endpoint node which is connected to the endpoint in the mic
-       node. The reg value muset be 0.
-- i80-if-timings: specify whether the panel which is connected to decon uses
-                 i80 lcd interface or mipi video interface. This node contains
-                 no timing information as that of fimd does. Because there is
-                 no register in decon to specify i80 interface timing value,
-                 it is not needed, but make it remain to use same kind of node
-                 in fimd and exynos7 decon.
-
-Example:
-SoC specific DT entry:
-decon: decon@13800000 {
-       compatible = "samsung,exynos5433-decon";
-       reg = <0x13800000 0x2104>;
-       clocks = <&cmu_disp CLK_ACLK_DECON>, <&cmu_disp CLK_ACLK_SMMU_DECON0X>,
-               <&cmu_disp CLK_ACLK_XIU_DECON0X>,
-               <&cmu_disp CLK_PCLK_SMMU_DECON0X>,
-               <&cmu_disp CLK_SCLK_DECON_VCLK>,
-               <&cmu_disp CLK_SCLK_DECON_ECLK>;
-       clock-names = "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x",
-               "pclk_smmu_decon0x", "sclk_decon_vclk", "sclk_decon_eclk";
-       interrupt-names = "vsync", "lcd_sys";
-       interrupts = <0 202 0>, <0 203 0>;
-
-       ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-                       decon_to_mic: endpoint {
-                               remote-endpoint = <&mic_to_decon>;
-                       };
-               };
-       };
-};
-
-Board specific DT entry:
-&decon {
-       i80-if-timings {
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/exynos7-decon.txt b/Documentation/devicetree/bindings/video/exynos7-decon.txt
deleted file mode 100644 (file)
index f5f9c8d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON)
-
-DECON (Display and Enhancement Controller) is the Display Controller for the
-Exynos7 series of SoCs which transfers the image data from a video memory
-buffer to an external LCD interface.
-
-Required properties:
-- compatible: value should be "samsung,exynos7-decon";
-
-- reg: physical base address and length of the DECON registers set.
-
-- interrupt-parent: should be the phandle of the decon controller's
-               parent interrupt controller.
-
-- interrupts: should contain a list of all DECON IP block interrupts in the
-                order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
-                format depends on the interrupt controller used.
-
-- interrupt-names: should contain the interrupt names: "fifo", "vsync",
-       "lcd_sys", in the same order as they were listed in the interrupts
-        property.
-
-- pinctrl-0: pin control group to be used for this controller.
-
-- pinctrl-names: must contain a "default" entry.
-
-- clocks: must include clock specifiers corresponding to entries in the
-         clock-names property.
-
-- clock-names: list of clock names sorted in the same order as the clocks
-               property. Must contain "pclk_decon0", "aclk_decon0",
-              "decon0_eclk", "decon0_vclk".
-- i80-if-timings: timing configuration for lcd i80 interface support.
-
-Optional Properties:
-- samsung,power-domain: a phandle to DECON power domain node.
-- display-timings: timing settings for DECON, as described in document [1].
-               Can be used in case timings cannot be provided otherwise
-               or to override timings provided by the panel.
-
-[1]: Documentation/devicetree/bindings/video/display-timing.txt
-
-Example:
-
-SoC specific DT entry:
-
-       decon@13930000 {
-               compatible = "samsung,exynos7-decon";
-               interrupt-parent = <&combiner>;
-               reg = <0x13930000 0x1000>;
-               interrupt-names = "lcd_sys", "vsync", "fifo";
-               interrupts = <0 188 0>, <0 189 0>, <0 190 0>;
-               clocks = <&clock_disp PCLK_DECON_INT>,
-                        <&clock_disp ACLK_DECON_INT>,
-                        <&clock_disp SCLK_DECON_INT_ECLK>,
-                        <&clock_disp SCLK_DECON_INT_EXTCLKPLL>;
-               clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk",
-                               "decon0_vclk";
-               status = "disabled";
-       };
-
-Board specific DT entry:
-
-       decon@13930000 {
-               pinctrl-0 = <&lcd_clk &pwm1_out>;
-               pinctrl-names = "default";
-               status = "okay";
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
deleted file mode 100644 (file)
index 7a3a9cd..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-The Exynos display port interface should be configured based on
-the type of panel connected to it.
-
-We use two nodes:
-       -dp-controller node
-       -dptx-phy node(defined inside dp-controller node)
-
-For the DP-PHY initialization, we use the dptx-phy node.
-Required properties for dptx-phy: deprecated, use phys and phy-names
-       -reg: deprecated
-               Base address of DP PHY register.
-       -samsung,enable-mask: deprecated
-               The bit-mask used to enable/disable DP PHY.
-
-For the Panel initialization, we read data from dp-controller node.
-Required properties for dp-controller:
-       -compatible:
-               should be "samsung,exynos5-dp".
-       -reg:
-               physical base address of the controller and length
-               of memory mapped region.
-       -interrupts:
-               interrupt combiner values.
-       -clocks:
-               from common clock binding: handle to dp clock.
-       -clock-names:
-               from common clock binding: Shall be "dp".
-       -interrupt-parent:
-               phandle to Interrupt combiner node.
-       -phys:
-               from general PHY binding: the phandle for the PHY device.
-       -phy-names:
-               from general PHY binding: Should be "dp".
-       -samsung,color-space:
-               input video data format.
-                       COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2
-       -samsung,dynamic-range:
-               dynamic range for input video data.
-                       VESA = 0, CEA = 1
-       -samsung,ycbcr-coeff:
-               YCbCr co-efficients for input video.
-                       COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1
-       -samsung,color-depth:
-               number of bits per colour component.
-                       COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3
-       -samsung,link-rate:
-               link rate supported by the panel.
-                       LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A
-       -samsung,lane-count:
-               number of lanes supported by the panel.
-                       LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
-       - display-timings: timings for the connected panel as described by
-               Documentation/devicetree/bindings/video/display-timing.txt
-
-Optional properties for dp-controller:
-       -interlaced:
-               interlace scan mode.
-                       Progressive if defined, Interlaced if not defined
-       -vsync-active-high:
-               VSYNC polarity configuration.
-                       High if defined, Low if not defined
-       -hsync-active-high:
-               HSYNC polarity configuration.
-                       High if defined, Low if not defined
-       -samsung,hpd-gpio:
-               Hotplug detect GPIO.
-                       Indicates which GPIO should be used for hotplug
-                       detection
-       -video interfaces: Device node can contain video interface port
-                           nodes according to [1].
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-SOC specific portion:
-       dp-controller {
-               compatible = "samsung,exynos5-dp";
-               reg = <0x145b0000 0x10000>;
-               interrupts = <10 3>;
-               interrupt-parent = <&combiner>;
-               clocks = <&clock 342>;
-               clock-names = "dp";
-
-               phys = <&dp_phy>;
-               phy-names = "dp";
-       };
-
-Board Specific portion:
-       dp-controller {
-               samsung,color-space = <0>;
-               samsung,dynamic-range = <0>;
-               samsung,ycbcr-coeff = <0>;
-               samsung,color-depth = <1>;
-               samsung,link-rate = <0x0a>;
-               samsung,lane-count = <4>;
-
-               display-timings {
-                       native-mode = <&lcd_timing>;
-                       lcd_timing: 1366x768 {
-                               clock-frequency = <70589280>;
-                               hactive = <1366>;
-                               vactive = <768>;
-                               hfront-porch = <40>;
-                               hback-porch = <40>;
-                               hsync-len = <32>;
-                               vback-porch = <10>;
-                               vfront-porch = <12>;
-                               vsync-len = <6>;
-                       };
-               };
-
-               ports {
-                       port@0 {
-                               dp_out: endpoint {
-                                       remote-endpoint = <&bridge_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt
deleted file mode 100644 (file)
index 0be0362..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-Exynos MIPI DSI Master
-
-Required properties:
-  - compatible: value should be one of the following
-               "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
-               "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
-               "samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
-               "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
-               "samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
-  - reg: physical base address and length of the registers set for the device
-  - interrupts: should contain DSI interrupt
-  - clocks: list of clock specifiers, must contain an entry for each required
-    entry in clock-names
-  - clock-names: should include "bus_clk"and "sclk_mipi" entries
-                the use of "pll_clk" is deprecated
-  - phys: list of phy specifiers, must contain an entry for each required
-    entry in phy-names
-  - phy-names: should include "dsim" entry
-  - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
-  - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
-  - samsung,pll-clock-frequency: specifies frequency of the oscillator clock
-  - #address-cells, #size-cells: should be set respectively to <1> and <0>
-    according to DSI host bindings (see MIPI DSI bindings [1])
-
-Optional properties:
-  - power-domains: a phandle to DSIM power domain node
-
-Child nodes:
-  Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
-
-Video interfaces:
-  Device node can contain video interface port nodes according to [2].
-  The following are properties specific to those nodes:
-
-  port node inbound:
-    - reg: (required) must be 0.
-  port node outbound:
-    - reg: (required) must be 1.
-
-  endpoint node connected from mic node (reg = 0):
-    - remote-endpoint: specifies the endpoint in mic node. This node is required
-                      for Exynos5433 mipi dsi. So mic can access to panel node
-                      thoughout this dsi node.
-  endpoint node connected to panel node (reg = 1):
-    - remote-endpoint: specifies the endpoint in panel node. This node is
-                      required in all kinds of exynos mipi dsi to represent
-                      the connection between mipi dsi and panel.
-    - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
-      mode
-    - samsung,esc-clock-frequency: specifies DSI frequency in escape mode
-
-[1]: Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
-[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-       dsi@11C80000 {
-               compatible = "samsung,exynos4210-mipi-dsi";
-               reg = <0x11C80000 0x10000>;
-               interrupts = <0 79 0>;
-               clocks = <&clock 286>, <&clock 143>;
-               clock-names = "bus_clk", "sclk_mipi";
-               phys = <&mipi_phy 1>;
-               phy-names = "dsim";
-               vddcore-supply = <&vusb_reg>;
-               vddio-supply = <&vmipi_reg>;
-               power-domains = <&pd_lcd0>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               samsung,pll-clock-frequency = <24000000>;
-
-               panel@1 {
-                       reg = <0>;
-                       ...
-                       port {
-                               panel_ep: endpoint {
-                                       remote-endpoint = <&dsi_ep>;
-                               };
-                       };
-               };
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-                               decon_to_mic: endpoint {
-                                       remote-endpoint = <&mic_to_decon>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-                               dsi_ep: endpoint {
-                                       reg = <0>;
-                                       samsung,burst-clock-frequency = <500000000>;
-                                       samsung,esc-clock-frequency = <20000000>;
-                                       remote-endpoint = <&panel_ep>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
deleted file mode 100644 (file)
index 1fd8cf9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-Device-Tree bindings for drm hdmi driver
-
-Required properties:
-- compatible: value should be one among the following:
-       1) "samsung,exynos5-hdmi" <DEPRECATED>
-       2) "samsung,exynos4210-hdmi"
-       3) "samsung,exynos4212-hdmi"
-       4) "samsung,exynos5420-hdmi"
-- reg: physical base address of the hdmi and length of memory mapped
-       region.
-- interrupts: interrupt number to the cpu.
-- hpd-gpio: following information about the hotplug gpio pin.
-       a) phandle of the gpio controller node.
-       b) pin number within the gpio controller.
-       c) optional flags and pull up/down.
-- clocks: list of clock IDs from SoC clock driver.
-       a) hdmi: Gate of HDMI IP bus clock.
-       b) sclk_hdmi: Gate of HDMI special clock.
-       c) sclk_pixel: Pixel special clock, one of the two possible inputs of
-               HDMI clock mux.
-       d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
-               HDMI clock mux.
-       e) mout_hdmi: It is required by the driver to switch between the 2
-               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
-               after configuration, parent is set to sclk_hdmiphy else
-               sclk_pixel.
-- clock-names: aliases as per driver requirements for above clock IDs:
-       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
-- ddc: phandle to the hdmi ddc node
-- phy: phandle to the hdmi phy node
-- samsung,syscon-phandle: phandle for system controller node for PMU.
-
-Example:
-
-       hdmi {
-               compatible = "samsung,exynos4212-hdmi";
-               reg = <0x14530000 0x100000>;
-               interrupts = <0 95 0>;
-               hpd-gpio = <&gpx3 7 1>;
-               ddc = <&hdmi_ddc_node>;
-               phy = <&hdmi_phy_node>;
-               samsung,syscon-phandle = <&pmu_system_controller>;
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt b/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt
deleted file mode 100644 (file)
index 41eee97..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Device-Tree bindings for hdmiddc driver
-
-Required properties:
-- compatible: value should be one of the following
-       1) "samsung,exynos5-hdmiddc" <DEPRECATED>
-       2) "samsung,exynos4210-hdmiddc"
-
-- reg: I2C address of the hdmiddc device.
-
-Example:
-
-       hdmiddc {
-               compatible = "samsung,exynos4210-hdmiddc";
-               reg = <0x50>;
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt b/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt
deleted file mode 100644 (file)
index 162f641..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Device-Tree bindings for hdmiphy driver
-
-Required properties:
-- compatible: value should be one of the following:
-       1) "samsung,exynos5-hdmiphy" <DEPRECATED>
-       2) "samsung,exynos4210-hdmiphy".
-       3) "samsung,exynos4212-hdmiphy".
-- reg: I2C address of the hdmiphy device.
-
-Example:
-
-       hdmiphy {
-               compatible = "samsung,exynos4210-hdmiphy";
-               reg = <0x38>;
-       };
diff --git a/Documentation/devicetree/bindings/video/exynos_mixer.txt b/Documentation/devicetree/bindings/video/exynos_mixer.txt
deleted file mode 100644 (file)
index 3e38128..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Device-Tree bindings for mixer driver
-
-Required properties:
-- compatible: value should be one of the following:
-       1) "samsung,exynos5-mixer" <DEPRECATED>
-       2) "samsung,exynos4210-mixer"
-       3) "samsung,exynos4212-mixer"
-       4) "samsung,exynos5250-mixer"
-       5) "samsung,exynos5420-mixer"
-
-- reg: physical base address of the mixer and length of memory mapped
-       region.
-- interrupts: interrupt number to the cpu.
-- clocks: list of clock IDs from SoC clock driver.
-       a) mixer: Gate of Mixer IP bus clock.
-       b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of
-               mixer mux.
-       c) hdmi: Gate of HDMI IP bus clock, needed together with sclk_hdmi.
-
-Example:
-
-       mixer {
-               compatible = "samsung,exynos5250-mixer";
-               reg = <0x14450000 0x10000>;
-               interrupts = <0 94 0>;
-       };
diff --git a/Documentation/devicetree/bindings/video/fsl,dcu.txt b/Documentation/devicetree/bindings/video/fsl,dcu.txt
deleted file mode 100644 (file)
index ebf1be9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Device Tree bindings for Freescale DCU DRM Driver
-
-Required properties:
-- compatible:          Should be one of
-       * "fsl,ls1021a-dcu".
-       * "fsl,vf610-dcu".
-
-- reg:                 Address and length of the register set for dcu.
-- clocks:              From common clock binding: handle to dcu clock.
-- clock-names:         From common clock binding: Shall be "dcu".
-- big-endian           Boolean property, LS1021A DCU registers are big-endian.
-- fsl,panel:           The phandle to panel node.
-
-Examples:
-dcu: dcu@2ce0000 {
-       compatible = "fsl,ls1021a-dcu";
-       reg = <0x0 0x2ce0000 0x0 0x10000>;
-       clocks = <&platform_clk 0>;
-       clock-names = "dcu";
-       big-endian;
-       fsl,panel = <&panel>;
-};
diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
deleted file mode 100644 (file)
index 8c8c2f4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Freescale imx21 Framebuffer
-
-This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
-
-Required properties:
-- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : One interrupt of the fb dev
-
-Required nodes:
-- display: Phandle to a display node as described in
-       Documentation/devicetree/bindings/video/display-timing.txt
-       Additional, the display node has to define properties:
-       - bits-per-pixel: Bits per pixel
-       - fsl,pcr: LCDC PCR value
-
-Optional properties:
-- lcd-supply: Regulator for LCD supply voltage.
-- fsl,dmacr: DMA Control Register value. This is optional. By default, the
-       register is not modified as recommended by the datasheet.
-- fsl,lpccr: Contrast Control Register value. This property provides the
-       default value for the contrast control register.
-       If that property is omitted, the register is zeroed.
-- fsl,lscr1: LCDC Sharp Configuration Register value.
-
-Example:
-
-       imxfb: fb@10021000 {
-               compatible = "fsl,imx21-fb";
-               interrupts = <61>;
-               reg = <0x10021000 0x1000>;
-               display = <&display0>;
-       };
-
-       ...
-
-       display0: display0 {
-               model = "Primeview-PD050VL1";
-               native-mode = <&timing_disp0>;
-               bits-per-pixel = <16>;
-               fsl,pcr = <0xf0c88080>; /* non-standard but required */
-               display-timings {
-                       timing_disp0: 640x480 {
-                               hactive = <640>;
-                               vactive = <480>;
-                               hback-porch = <112>;
-                               hfront-porch = <36>;
-                               hsync-len = <32>;
-                               vback-porch = <33>;
-                               vfront-porch = <33>;
-                               vsync-len = <2>;
-                               clock-frequency = <25000000>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/hdmi-connector.txt b/Documentation/devicetree/bindings/video/hdmi-connector.txt
deleted file mode 100644 (file)
index acd5668..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-HDMI Connector
-==============
-
-Required properties:
-- compatible: "hdmi-connector"
-- type: the HDMI connector type: "a", "b", "c", "d" or "e"
-
-Optional properties:
-- label: a symbolic name for the connector
-- hpd-gpios: HPD GPIO number
-
-Required nodes:
-- Video port for HDMI input
-
-Example
--------
-
-hdmi0: connector@1 {
-       compatible = "hdmi-connector";
-       label = "hdmi";
-
-       type = "a";
-
-       port {
-               hdmi_connector_in: endpoint {
-                       remote-endpoint = <&tpd12s015_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt b/Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt
deleted file mode 100644 (file)
index 1a1e653..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-LG.Philips LB035Q02 Panel
-=========================
-
-Required properties:
-- compatible: "lgphilips,lb035q02"
-- enable-gpios: panel enable gpio
-
-Optional properties:
-- label: a symbolic name for the panel
-
-Required nodes:
-- Video port for DPI input
-
-Example
--------
-
-lcd-panel: panel@0 {
-       compatible = "lgphilips,lb035q02";
-       reg = <0>;
-       spi-max-frequency = <100000>;
-       spi-cpol;
-       spi-cpha;
-
-       label = "lcd";
-
-       enable-gpios = <&gpio7 7 0>;
-
-       port {
-               lcd_in: endpoint {
-                       remote-endpoint = <&dpi_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/panel-dpi.txt b/Documentation/devicetree/bindings/video/panel-dpi.txt
deleted file mode 100644 (file)
index a40180b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-Generic MIPI DPI Panel
-======================
-
-Required properties:
-- compatible: "panel-dpi"
-
-Optional properties:
-- label: a symbolic name for the panel
-- enable-gpios: panel enable gpio
-
-Required nodes:
-- "panel-timing" containing video timings
-  (Documentation/devicetree/bindings/video/display-timing.txt)
-- Video port for DPI input
-
-Example
--------
-
-lcd0: display@0 {
-        compatible = "samsung,lte430wq-f0c", "panel-dpi";
-        label = "lcd";
-
-        port {
-            lcd_in: endpoint {
-                    remote-endpoint = <&dpi_out>;
-            };
-        };
-
-        panel-timing {
-                clock-frequency = <9200000>;
-                hactive = <480>;
-                vactive = <272>;
-                hfront-porch = <8>;
-                hback-porch = <4>;
-                hsync-len = <41>;
-                vback-porch = <2>;
-                vfront-porch = <4>;
-                vsync-len = <10>;
-
-                hsync-active = <0>;
-                vsync-active = <0>;
-                de-active = <1>;
-                pixelclk-active = <1>;
-        };
-};
diff --git a/Documentation/devicetree/bindings/video/panel-dsi-cm.txt b/Documentation/devicetree/bindings/video/panel-dsi-cm.txt
deleted file mode 100644 (file)
index dce48eb..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Generic MIPI DSI Command Mode Panel
-===================================
-
-Required properties:
-- compatible: "panel-dsi-cm"
-
-Optional properties:
-- label: a symbolic name for the panel
-- reset-gpios: panel reset gpio
-- te-gpios: panel TE gpio
-
-Required nodes:
-- Video port for DSI input
-
-Example
--------
-
-lcd0: display {
-       compatible = "tpo,taal", "panel-dsi-cm";
-       label = "lcd0";
-
-       reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
-
-       port {
-               lcd0_in: endpoint {
-                       remote-endpoint = <&dsi1_out_ep>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/renesas,du.txt b/Documentation/devicetree/bindings/video/renesas,du.txt
deleted file mode 100644 (file)
index c902323..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-* Renesas R-Car Display Unit (DU)
-
-Required Properties:
-
-  - compatible: must be one of the following.
-    - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
-    - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
-    - "renesas,du-r8a7791" for R8A7791 (R-Car M2) compatible DU
-
-  - reg: A list of base address and length of each memory resource, one for
-    each entry in the reg-names property.
-  - reg-names: Name of the memory resources. The DU requires one memory
-    resource for the DU core (named "du") and one memory resource for each
-    LVDS encoder (named "lvds.x" with "x" being the LVDS controller numerical
-    index).
-
-  - interrupt-parent: phandle of the parent interrupt controller.
-  - interrupts: Interrupt specifiers for the DU interrupts.
-
-  - clocks: A list of phandles + clock-specifier pairs, one for each entry in
-    the clock-names property.
-  - clock-names: Name of the clocks. This property is model-dependent.
-    - R8A7779 uses a single functional clock. The clock doesn't need to be
-      named.
-    - R8A7790 and R8A7791 use one functional clock per channel and one clock
-      per LVDS encoder. The functional clocks must be named "du.x" with "x"
-      being the channel numerical index. The LVDS clocks must be named
-      "lvds.x" with "x" being the LVDS encoder numerical index.
-    - In addition to the functional and encoder clocks, all DU versions also
-      support externally supplied pixel clocks. Those clocks are optional.
-      When supplied they must be named "dclkin.x" with "x" being the input
-      clock numerical index.
-
-Required nodes:
-
-The connections to the DU output video ports are modeled using the OF graph
-bindings specified in Documentation/devicetree/bindings/graph.txt.
-
-The following table lists for each supported model the port number
-corresponding to each DU output.
-
-               Port 0          Port1           Port2
------------------------------------------------------------------------------
- R8A7779 (H1)  DPAD 0          DPAD 1          -
- R8A7790 (H2)  DPAD            LVDS 0          LVDS 1
- R8A7791 (M2)  DPAD            LVDS 0          -
-
-
-Example: R8A7790 (R-Car H2) DU
-
-       du: du@feb00000 {
-               compatible = "renesas,du-r8a7790";
-               reg = <0 0xfeb00000 0 0x70000>,
-                     <0 0xfeb90000 0 0x1c>,
-                     <0 0xfeb94000 0 0x1c>;
-               reg-names = "du", "lvds.0", "lvds.1";
-               interrupt-parent = <&gic>;
-               interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
-                            <0 268 IRQ_TYPE_LEVEL_HIGH>,
-                            <0 269 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&mstp7_clks R8A7790_CLK_DU0>,
-                        <&mstp7_clks R8A7790_CLK_DU1>,
-                        <&mstp7_clks R8A7790_CLK_DU2>,
-                        <&mstp7_clks R8A7790_CLK_LVDS0>,
-                        <&mstp7_clks R8A7790_CLK_LVDS1>;
-               clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-                               du_out_rgb: endpoint {
-                               };
-                       };
-                       port@1 {
-                               reg = <1>;
-                               du_out_lvds0: endpoint {
-                               };
-                       };
-                       port@2 {
-                               reg = <2>;
-                               du_out_lvds1: endpoint {
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/rockchip-drm.txt b/Documentation/devicetree/bindings/video/rockchip-drm.txt
deleted file mode 100644 (file)
index 7fff582..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Rockchip DRM master device
-================================
-
-The Rockchip DRM master device is a virtual device needed to list all
-vop devices or other display interface nodes that comprise the
-graphics subsystem.
-
-Required properties:
-- compatible: Should be "rockchip,display-subsystem"
-- ports: Should contain a list of phandles pointing to display interface port
-  of vop devices. vop definitions as defined in
-  Documentation/devicetree/bindings/video/rockchip-vop.txt
-
-example:
-
-display-subsystem {
-       compatible = "rockchip,display-subsystem";
-       ports = <&vopl_out>, <&vopb_out>;
-};
diff --git a/Documentation/devicetree/bindings/video/rockchip-vop.txt b/Documentation/devicetree/bindings/video/rockchip-vop.txt
deleted file mode 100644 (file)
index d15351f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-device-tree bindings for rockchip soc display controller (vop)
-
-VOP (Visual Output Processor) is the Display Controller for the Rockchip
-series of SoCs which transfers the image data from a video memory
-buffer to an external LCD interface.
-
-Required properties:
-- compatible: value should be one of the following
-               "rockchip,rk3288-vop";
-
-- interrupts: should contain a list of all VOP IP block interrupts in the
-                order: VSYNC, LCD_SYSTEM. The interrupt specifier
-                format depends on the interrupt controller used.
-
-- clocks: must include clock specifiers corresponding to entries in the
-               clock-names property.
-
-- clock-names: Must contain
-               aclk_vop: for ddr buffer transfer.
-               hclk_vop: for ahb bus to R/W the phy regs.
-               dclk_vop: pixel clock.
-
-- resets: Must contain an entry for each entry in reset-names.
-  See ../reset/reset.txt for details.
-- reset-names: Must include the following entries:
-  - axi
-  - ahb
-  - dclk
-
-- iommus: required a iommu node
-
-- port: A port node with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Example:
-SoC specific DT entry:
-       vopb: vopb@ff930000 {
-               compatible = "rockchip,rk3288-vop";
-               reg = <0xff930000 0x19c>;
-               interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
-               clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
-               resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>;
-               reset-names = "axi", "ahb", "dclk";
-               iommus = <&vopb_mmu>;
-               vopb_out: port {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       vopb_out_edp: endpoint@0 {
-                               reg = <0>;
-                               remote-endpoint=<&edp_in_vopb>;
-                       };
-                       vopb_out_hdmi: endpoint@1 {
-                               reg = <1>;
-                               remote-endpoint=<&hdmi_in_vopb>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt
deleted file mode 100644 (file)
index a8bbbde..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-Device-Tree bindings for Samsung SoC display controller (FIMD)
-
-FIMD (Fully Interactive Mobile Display) is the Display Controller for the
-Samsung series of SoCs which transfers the image data from a video memory
-buffer to an external LCD interface.
-
-Required properties:
-- compatible: value should be one of the following
-               "samsung,s3c2443-fimd"; /* for S3C24XX SoCs */
-               "samsung,s3c6400-fimd"; /* for S3C64XX SoCs */
-               "samsung,s5pv210-fimd"; /* for S5PV210 SoC */
-               "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
-               "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
-               "samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
-               "samsung,exynos5250-fimd"; /* for Exynos5 SoCs */
-
-- reg: physical base address and length of the FIMD registers set.
-
-- interrupt-parent: should be the phandle of the fimd controller's
-               parent interrupt controller.
-
-- interrupts: should contain a list of all FIMD IP block interrupts in the
-                order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
-                format depends on the interrupt controller used.
-
-- interrupt-names: should contain the interrupt names: "fifo", "vsync",
-       "lcd_sys", in the same order as they were listed in the interrupts
-        property.
-
-- pinctrl-0: pin control group to be used for this controller.
-
-- pinctrl-names: must contain a "default" entry.
-
-- clocks: must include clock specifiers corresponding to entries in the
-         clock-names property.
-
-- clock-names: list of clock names sorted in the same order as the clocks
-               property. Must contain "sclk_fimd" and "fimd".
-
-Optional Properties:
-- power-domains: a phandle to FIMD power domain node.
-- samsung,invert-vden: video enable signal is inverted
-- samsung,invert-vclk: video clock signal is inverted
-- display-timings: timing settings for FIMD, as described in document [1].
-               Can be used in case timings cannot be provided otherwise
-               or to override timings provided by the panel.
-- samsung,sysreg: handle to syscon used to control the system registers
-- i80-if-timings: timing configuration for lcd i80 interface support.
-  - cs-setup: clock cycles for the active period of address signal is enabled
-              until chip select is enabled.
-              If not specified, the default value(0) will be used.
-  - wr-setup: clock cycles for the active period of CS signal is enabled until
-              write signal is enabled.
-              If not specified, the default value(0) will be used.
-  - wr-active: clock cycles for the active period of CS is enabled.
-               If not specified, the default value(1) will be used.
-  - wr-hold: clock cycles for the active period of CS is disabled until write
-             signal is disabled.
-             If not specified, the default value(0) will be used.
-
-  The parameters are defined as:
-
-    VCLK(internal)  __|??????|_____|??????|_____|??????|_____|??????|_____|??
-                      :            :            :            :            :
-    Address Output  --:<XXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XX
-                      | cs-setup+1 |            :            :            :
-                      |<---------->|            :            :            :
-    Chip Select     ???????????????|____________:____________:____________|??
-                                   | wr-setup+1 |            | wr-hold+1  |
-                                   |<---------->|            |<---------->|
-    Write Enable    ????????????????????????????|____________|???????????????
-                                                | wr-active+1|
-                                                |<---------->|
-    Video Data      ----------------------------<XXXXXXXXXXXXXXXXXXXXXXXXX>--
-
-The device node can contain 'port' child nodes according to the bindings defined
-in [2]. The following are properties specific to those nodes:
-- reg: (required) port index, can be:
-               0 - for CAMIF0 input,
-               1 - for CAMIF1 input,
-               2 - for CAMIF2 input,
-               3 - for parallel output,
-               4 - for write-back interface
-
-[1]: Documentation/devicetree/bindings/video/display-timing.txt
-[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-SoC specific DT entry:
-
-       fimd@11c00000 {
-               compatible = "samsung,exynos4210-fimd";
-               interrupt-parent = <&combiner>;
-               reg = <0x11c00000 0x20000>;
-               interrupt-names = "fifo", "vsync", "lcd_sys";
-               interrupts = <11 0>, <11 1>, <11 2>;
-               clocks = <&clock 140>, <&clock 283>;
-               clock-names = "sclk_fimd", "fimd";
-               power-domains = <&pd_lcd0>;
-               status = "disabled";
-       };
-
-Board specific DT entry:
-
-       fimd@11c00000 {
-               pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
-               pinctrl-names = "default";
-               status = "okay";
-       };
diff --git a/Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt b/Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt
deleted file mode 100644 (file)
index 0cc8981..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-SHARP LS037V7DW01 TFT-LCD panel
-===================================
-
-Required properties:
-- compatible: "sharp,ls037v7dw01"
-
-Optional properties:
-- label: a symbolic name for the panel
-- enable-gpios: a GPIO spec for the optional enable pin.
-  This pin is the INI pin as specified in the LS037V7DW01.pdf file.
-- reset-gpios: a GPIO spec for the optional reset pin.
-  This pin is the RESB pin as specified in the LS037V7DW01.pdf file.
-- mode-gpios: a GPIO
-  ordered MO, LR, and UD as specified in the LS037V7DW01.pdf file.
-
-Required nodes:
-- Video port for DPI input
-
-This panel can have zero to five GPIOs to configure to change configuration
-between QVGA and VGA mode and the scan direction. As these pins can be also
-configured with external pulls, all the GPIOs are considered optional with holes
-in the array.
-
-Example
--------
-
-Example when connected to a omap2+ based device:
-
-lcd0: display {
-       compatible = "sharp,ls037v7dw01";
-       power-supply = <&lcd_3v3>;
-       enable-gpios = <&gpio5 24 GPIO_ACTIVE_HIGH>;    /* gpio152, lcd INI */
-       reset-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;     /* gpio155, lcd RESB */
-       mode-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH        /* gpio154, lcd MO */
-                     &gpio1 2 GPIO_ACTIVE_HIGH         /* gpio2, lcd LR */
-                     &gpio1 3 GPIO_ACTIVE_HIGH>;       /* gpio3, lcd UD */
-
-       port {
-               lcd_in: endpoint {
-                       remote-endpoint = <&dpi_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt
deleted file mode 100644 (file)
index c46ba64..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Sunxi specific Simple Framebuffer bindings
-
-This binding documents sunxi specific extensions to the simple-framebuffer
-bindings. The sunxi simplefb u-boot code relies on the devicetree containing
-pre-populated simplefb nodes.
-
-These extensions are intended so that u-boot can select the right node based
-on which pipeline is being used. As such they are solely intended for
-firmware / bootloader use, and the OS should ignore them.
-
-Required properties:
-- compatible: "allwinner,simple-framebuffer"
-- allwinner,pipeline, one of:
-  "de_be0-lcd0"
-  "de_be1-lcd1"
-  "de_be0-lcd0-hdmi"
-  "de_be1-lcd1-hdmi"
-
-Example:
-
-chosen {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       ranges;
-
-       framebuffer@0 {
-               compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
-               allwinner,pipeline = "de_be0-lcd0-hdmi";
-               clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
-                        <&ahb_gates 44>;
-               status = "disabled";
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt
deleted file mode 100644 (file)
index 4474ef6..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-Simple Framebuffer
-
-A simple frame-buffer describes a frame-buffer setup by firmware or
-the bootloader, with the assumption that the display hardware has already
-been set up to scan out from the memory pointed to by the reg property.
-
-Since simplefb nodes represent runtime information they must be sub-nodes of
-the chosen node (*). Simplefb nodes must be named "framebuffer@<address>".
-
-If the devicetree contains nodes for the display hardware used by a simplefb,
-then the simplefb node must contain a property called "display", which
-contains a phandle pointing to the primary display hw node, so that the OS
-knows which simplefb to disable when handing over control to a driver for the
-real hardware. The bindings for the hw nodes must specify which node is
-considered the primary node.
-
-It is advised to add display# aliases to help the OS determine how to number
-things. If display# aliases are used, then if the simplefb node contains a
-"display" property then the /aliases/display# path must point to the display
-hw node the "display" property points to, otherwise it must point directly
-to the simplefb node.
-
-If a simplefb node represents the preferred console for user interaction,
-then the chosen node's stdout-path property should point to it, or to the
-primary display hw node, as with display# aliases. If display aliases are
-used then it should be set to the alias instead.
-
-It is advised that devicetree files contain pre-filled, disabled framebuffer
-nodes, so that the firmware only needs to update the mode information and
-enable them. This way if e.g. later on support for more display clocks get
-added, the simplefb nodes will already contain this info and the firmware
-does not need to be updated.
-
-If pre-filled framebuffer nodes are used, the firmware may need extra
-information to find the right node. In that case an extra platform specific
-compatible and platform specific properties should be used and documented,
-see e.g. simple-framebuffer-sunxi.txt .
-
-Required properties:
-- compatible: "simple-framebuffer"
-- reg: Should contain the location and size of the framebuffer memory.
-- width: The width of the framebuffer in pixels.
-- height: The height of the framebuffer in pixels.
-- stride: The number of bytes in each line of the framebuffer.
-- format: The format of the framebuffer surface. Valid values are:
-  - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b).
-  - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
-
-Optional properties:
-- clocks : List of clocks used by the framebuffer. Clocks listed here
-           are expected to already be configured correctly. The OS must
-           ensure these clocks are not modified or disabled while the
-           simple framebuffer remains active.
-- display : phandle pointing to the primary display hardware node
-
-Example:
-
-aliases {
-       display0 = &lcdc0;
-}
-
-chosen {
-       framebuffer0: framebuffer@1d385000 {
-               compatible = "simple-framebuffer";
-               reg = <0x1d385000 (1600 * 1200 * 2)>;
-               width = <1600>;
-               height = <1200>;
-               stride = <(1600 * 2)>;
-               format = "r5g6b5";
-               clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
-               display = <&lcdc0>;
-       };
-       stdout-path = "display0";
-};
-
-soc@01c00000 {
-       lcdc0: lcdc@1c0c000 {
-               compatible = "allwinner,sun4i-a10-lcdc";
-               ...
-       };
-};
-
-
-*) Older devicetree files may have a compatible = "simple-framebuffer" node
-in a different place, operating systems must first enumerate any compatible
-nodes found under chosen and then check for other compatible nodes.
diff --git a/Documentation/devicetree/bindings/video/sony,acx565akm.txt b/Documentation/devicetree/bindings/video/sony,acx565akm.txt
deleted file mode 100644 (file)
index e123332..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Sony ACX565AKM SDI Panel
-========================
-
-Required properties:
-- compatible: "sony,acx565akm"
-
-Optional properties:
-- label: a symbolic name for the panel
-- reset-gpios: panel reset gpio
-
-Required nodes:
-- Video port for SDI input
-
-Example
--------
-
-acx565akm@2 {
-       compatible = "sony,acx565akm";
-       spi-max-frequency = <6000000>;
-       reg = <2>;
-
-       label = "lcd";
-       reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */
-
-       port {
-               lcd_in: endpoint {
-                       remote-endpoint = <&sdi_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/ssd1289fb.txt b/Documentation/devicetree/bindings/video/ssd1289fb.txt
deleted file mode 100644 (file)
index 4fcd5e6..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-* Solomon SSD1289 Framebuffer Driver
-
-Required properties:
-  - compatible: Should be "solomon,ssd1289fb". The only supported bus for
-    now is lbc.
-  - reg: Should contain address of the controller on the LBC bus. The detail
-    was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
-
-Examples:
-display@2,0 {
-       compatible = "solomon,ssd1289fb";
-       reg = <0x2 0x0000 0x0004>;
-};
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
deleted file mode 100644 (file)
index d1be78d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-* Solomon SSD1307 Framebuffer Driver
-
-Required properties:
-  - compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
-    now is i2c, and the supported chips are ssd1305, ssd1306 and ssd1307.
-  - reg: Should contain address of the controller on the I2C bus. Most likely
-         0x3c or 0x3d
-  - pwm: Should contain the pwm to use according to the OF device tree PWM
-         specification [0]. Only required for the ssd1307.
-  - reset-gpios: Should contain the GPIO used to reset the OLED display
-  - solomon,height: Height in pixel of the screen driven by the controller
-  - solomon,width: Width in pixel of the screen driven by the controller
-  - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is
-    mapped to.
-
-Optional properties:
-  - reset-active-low: Is the reset gpio is active on physical low?
-  - solomon,segment-no-remap: Display needs normal (non-inverted) data column
-                              to segment mapping
-  - solomon,com-seq: Display uses sequential COM pin configuration
-  - solomon,com-lrremap: Display uses left-right COM pin remap
-  - solomon,com-invdir: Display uses inverted COM pin scan direction
-  - solomon,com-offset: Number of the COM pin wired to the first display line
-  - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
-  - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
-                         This needs to be the higher, the higher the capacitance
-                         of the OLED's pixels is
-
-[0]: Documentation/devicetree/bindings/pwm/pwm.txt
-
-Examples:
-ssd1307: oled@3c {
-        compatible = "solomon,ssd1307fb-i2c";
-        reg = <0x3c>;
-        pwms = <&pwm 4 3000>;
-        reset-gpios = <&gpio2 7>;
-        reset-active-low;
-};
-
-ssd1306: oled@3c {
-        compatible = "solomon,ssd1306fb-i2c";
-        reg = <0x3c>;
-        pwms = <&pwm 4 3000>;
-        reset-gpios = <&gpio2 7>;
-        reset-active-low;
-        solomon,com-lrremap;
-        solomon,com-invdir;
-        solomon,com-offset = <32>;
-};
diff --git a/Documentation/devicetree/bindings/video/thine,thc63lvdm83d b/Documentation/devicetree/bindings/video/thine,thc63lvdm83d
deleted file mode 100644 (file)
index 527e236..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-THine Electronics THC63LVDM83D LVDS serializer
-----------------------------------------------
-
-The THC63LVDM83D is an LVDS serializer designed to support pixel data
-transmission between a host and a flat panel.
-
-Required properties:
-
-- compatible: Should be "thine,thc63lvdm83d"
-
-Optional properties:
-
-- pwdn-gpios: Power down control GPIO
-
-Required nodes:
-
-The THC63LVDM83D has two video ports. Their connections are modeled using the
-OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt.
-
-- Video port 0 for CMOS/TTL input
-- Video port 1 for LVDS output
-
-
-Example
--------
-
-       lvds_enc: encoder@0 {
-               compatible = "thine,thc63lvdm83d";
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-
-                               lvds_enc_in: endpoint@0 {
-                                       remote-endpoint = <&rgb_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-
-                               lvds_enc_out: endpoint@0 {
-                                       remote-endpoint = <&panel_in>;
-                               };
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/video/ti,dra7-dss.txt b/Documentation/devicetree/bindings/video/ti,dra7-dss.txt
deleted file mode 100644 (file)
index f33a051..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-Texas Instruments DRA7x Display Subsystem
-=========================================
-
-See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
-description about OMAP Display Subsystem bindings.
-
-DSS Core
---------
-
-Required properties:
-- compatible: "ti,dra7-dss"
-- reg: address and length of the register spaces for 'dss'
-- ti,hwmods: "dss_core"
-- clocks: handle to fclk
-- clock-names: "fck"
-- syscon: phandle to control module core syscon node
-
-Optional properties:
-
-Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties
-can be used to describe the video PLLs:
-
-- reg: address and length of the register spaces for 'pll1_clkctrl',
-  'pll1', 'pll2_clkctrl', 'pll2'
-- clocks: handle to video1 pll clock and video2 pll clock
-- clock-names: "video1_clk" and "video2_clk"
-
-Required nodes:
-- DISPC
-
-Optional nodes:
-- DSS Submodules: HDMI
-- Video port for DPI output
-
-DPI Endpoint required properties:
-- data-lines: number of lines used
-
-
-DISPC
------
-
-Required properties:
-- compatible: "ti,dra7-dispc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_dispc"
-- interrupts: the DISPC interrupt
-- clocks: handle to fclk
-- clock-names: "fck"
-
-HDMI
-----
-
-Required properties:
-- compatible: "ti,dra7-hdmi"
-- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
-       'core'
-- reg-names: "wp", "pll", "phy", "core"
-- interrupts: the HDMI interrupt line
-- ti,hwmods: "dss_hdmi"
-- vdda-supply: vdda power supply
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-Optional nodes:
-- Video port for HDMI output
-
-HDMI Endpoint optional properties:
-- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
-  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/video/ti,omap-dss.txt b/Documentation/devicetree/bindings/video/ti,omap-dss.txt
deleted file mode 100644 (file)
index e1ef295..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-Texas Instruments OMAP Display Subsystem
-========================================
-
-Generic Description
--------------------
-
-This document is a generic description of the OMAP Display Subsystem bindings.
-Binding details for each OMAP SoC version are described in respective binding
-documentation.
-
-The OMAP Display Subsystem (DSS) hardware consists of DSS Core, DISPC module and
-a number of encoder modules. All DSS versions contain DSS Core and DISPC, but
-the encoder modules vary.
-
-The DSS Core is the parent of the other DSS modules, and manages clock routing,
-integration to the SoC, etc.
-
-DISPC is the display controller, which reads pixels from the memory and outputs
-a RGB pixel stream to encoders.
-
-The encoder modules encode the received RGB pixel stream to a video output like
-HDMI, MIPI DPI, etc.
-
-Video Ports
------------
-
-The DSS Core and the encoders have video port outputs. The structure of the
-video ports is described in Documentation/devicetree/bindings/graph.txt,
-and the properties for the ports and endpoints for each encoder are
-described in the SoC's DSS binding documentation.
-
-The video ports are used to describe the connections to external hardware, like
-panels or external encoders.
-
-Aliases
--------
-
-The board dts file may define aliases for displays to assign "displayX" style
-name for each display. If no aliases are defined, a semi-random number is used
-for the display.
-
-Example
--------
-
-A shortened example of the DSS description for OMAP4, with non-relevant parts
-removed, defined in omap4.dtsi:
-
-dss: dss@58000000 {
-       compatible = "ti,omap4-dss";
-       reg = <0x58000000 0x80>;
-       status = "disabled";
-       ti,hwmods = "dss_core";
-       clocks = <&dss_dss_clk>;
-       clock-names = "fck";
-       #address-cells = <1>;
-       #size-cells = <1>;
-       ranges;
-
-       dispc@58001000 {
-               compatible = "ti,omap4-dispc";
-               reg = <0x58001000 0x1000>;
-               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-               ti,hwmods = "dss_dispc";
-               clocks = <&dss_dss_clk>;
-               clock-names = "fck";
-       };
-
-       hdmi: encoder@58006000 {
-               compatible = "ti,omap4-hdmi";
-               reg = <0x58006000 0x200>,
-                     <0x58006200 0x100>,
-                     <0x58006300 0x100>,
-                     <0x58006400 0x1000>;
-               reg-names = "wp", "pll", "phy", "core";
-               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-               status = "disabled";
-               ti,hwmods = "dss_hdmi";
-               clocks = <&dss_48mhz_clk>, <&dss_sys_clk>;
-               clock-names = "fck", "sys_clk";
-       };
-};
-
-A shortened example of the board description for OMAP4 Panda board, defined in
-omap4-panda.dts.
-
-The Panda board has a DVI and a HDMI connector, and the board contains a TFP410
-chip (MIPI DPI to DVI encoder) and a TPD12S015 chip (HDMI ESD protection & level
-shifter). The video pipelines for the connectors are formed as follows:
-
-DSS Core --(MIPI DPI)--> TFP410 --(DVI)--> DVI Connector
-OMAP HDMI --(HDMI)--> TPD12S015 --(HDMI)--> HDMI Connector
-
-/ {
-       aliases {
-               display0 = &dvi0;
-               display1 = &hdmi0;
-       };
-
-       tfp410: encoder@0 {
-               compatible = "ti,tfp410";
-               gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;     /* 0, power-down */
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&tfp410_pins>;
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-
-                               tfp410_in: endpoint@0 {
-                                       remote-endpoint = <&dpi_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-
-                               tfp410_out: endpoint@0 {
-                                       remote-endpoint = <&dvi_connector_in>;
-                               };
-                       };
-               };
-       };
-
-       dvi0: connector@0 {
-               compatible = "dvi-connector";
-               label = "dvi";
-
-               i2c-bus = <&i2c3>;
-
-               port {
-                       dvi_connector_in: endpoint {
-                               remote-endpoint = <&tfp410_out>;
-                       };
-               };
-       };
-
-       tpd12s015: encoder@1 {
-               compatible = "ti,tpd12s015";
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&tpd12s015_pins>;
-
-               gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
-                       <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
-                       <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-
-                               tpd12s015_in: endpoint@0 {
-                                       remote-endpoint = <&hdmi_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-
-                               tpd12s015_out: endpoint@0 {
-                                       remote-endpoint = <&hdmi_connector_in>;
-                               };
-                       };
-               };
-       };
-
-       hdmi0: connector@1 {
-               compatible = "hdmi-connector";
-               label = "hdmi";
-
-               port {
-                       hdmi_connector_in: endpoint {
-                               remote-endpoint = <&tpd12s015_out>;
-                       };
-               };
-       };
-};
-
-&dss {
-       status = "ok";
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&dss_dpi_pins>;
-
-       port {
-               dpi_out: endpoint {
-                       remote-endpoint = <&tfp410_in>;
-                       data-lines = <24>;
-               };
-       };
-};
-
-&hdmi {
-       status = "ok";
-       vdda-supply = <&vdac>;
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&dss_hdmi_pins>;
-
-       port {
-               hdmi_out: endpoint {
-                       remote-endpoint = <&tpd12s015_in>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/ti,omap2-dss.txt b/Documentation/devicetree/bindings/video/ti,omap2-dss.txt
deleted file mode 100644 (file)
index fa8bb2e..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-Texas Instruments OMAP2 Display Subsystem
-=========================================
-
-See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
-description about OMAP Display Subsystem bindings.
-
-DSS Core
---------
-
-Required properties:
-- compatible: "ti,omap2-dss"
-- reg: address and length of the register space
-- ti,hwmods: "dss_core"
-
-Optional nodes:
-- Video port for DPI output
-
-DPI Endpoint required properties:
-- data-lines: number of lines used
-
-
-DISPC
------
-
-Required properties:
-- compatible: "ti,omap2-dispc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_dispc"
-- interrupts: the DISPC interrupt
-
-
-RFBI
-----
-
-Required properties:
-- compatible: "ti,omap2-rfbi"
-- reg: address and length of the register space
-- ti,hwmods: "dss_rfbi"
-
-
-VENC
-----
-
-Required properties:
-- compatible: "ti,omap2-venc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_venc"
-- vdda-supply: power supply for DAC
-
-VENC Endpoint required properties:
-
-Required properties:
-- ti,invert-polarity: invert the polarity of the video signal
-- ti,channels: 1 for composite, 2 for s-video
diff --git a/Documentation/devicetree/bindings/video/ti,omap3-dss.txt b/Documentation/devicetree/bindings/video/ti,omap3-dss.txt
deleted file mode 100644 (file)
index 0023fa4..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-Texas Instruments OMAP3 Display Subsystem
-=========================================
-
-See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
-description about OMAP Display Subsystem bindings.
-
-DSS Core
---------
-
-Required properties:
-- compatible: "ti,omap3-dss"
-- reg: address and length of the register space
-- ti,hwmods: "dss_core"
-- clocks: handle to fclk
-- clock-names: "fck"
-
-Optional nodes:
-- Video ports:
-       - Port 0: DPI output
-       - Port 1: SDI output
-
-DPI Endpoint required properties:
-- data-lines: number of lines used
-
-SDI Endpoint required properties:
-- datapairs: number of datapairs used
-
-
-DISPC
------
-
-Required properties:
-- compatible: "ti,omap3-dispc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_dispc"
-- interrupts: the DISPC interrupt
-- clocks: handle to fclk
-- clock-names: "fck"
-
-
-RFBI
-----
-
-Required properties:
-- compatible: "ti,omap3-rfbi"
-- reg: address and length of the register space
-- ti,hwmods: "dss_rfbi"
-- clocks: handles to fclk and iclk
-- clock-names: "fck", "ick"
-
-
-VENC
-----
-
-Required properties:
-- compatible: "ti,omap3-venc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_venc"
-- vdda-supply: power supply for DAC
-- clocks: handle to fclk
-- clock-names: "fck"
-
-VENC Endpoint required properties:
-- ti,invert-polarity: invert the polarity of the video signal
-- ti,channels: 1 for composite, 2 for s-video
-
-
-DSI
----
-
-Required properties:
-- compatible: "ti,omap3-dsi"
-- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
-- reg-names: "proto", "phy", "pll"
-- interrupts: the DSI interrupt line
-- ti,hwmods: "dss_dsi1"
-- vdd-supply: power supply for DSI
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-DSI Endpoint required properties:
-- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
-  DATA1+, DATA1-, ...
diff --git a/Documentation/devicetree/bindings/video/ti,omap4-dss.txt b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt
deleted file mode 100644 (file)
index b8c29fb..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-Texas Instruments OMAP4 Display Subsystem
-=========================================
-
-See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
-description about OMAP Display Subsystem bindings.
-
-DSS Core
---------
-
-Required properties:
-- compatible: "ti,omap4-dss"
-- reg: address and length of the register space
-- ti,hwmods: "dss_core"
-- clocks: handle to fclk
-- clock-names: "fck"
-
-Required nodes:
-- DISPC
-
-Optional nodes:
-- DSS Submodules: RFBI, VENC, DSI, HDMI
-- Video port for DPI output
-
-DPI Endpoint required properties:
-- data-lines: number of lines used
-
-
-DISPC
------
-
-Required properties:
-- compatible: "ti,omap4-dispc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_dispc"
-- interrupts: the DISPC interrupt
-- clocks: handle to fclk
-- clock-names: "fck"
-
-
-RFBI
-----
-
-Required properties:
-- compatible: "ti,omap4-rfbi"
-- reg: address and length of the register space
-- ti,hwmods: "dss_rfbi"
-- clocks: handles to fclk and iclk
-- clock-names: "fck", "ick"
-
-Optional nodes:
-- Video port for RFBI output
-- RFBI controlled peripherals
-
-
-VENC
-----
-
-Required properties:
-- compatible: "ti,omap4-venc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_venc"
-- vdda-supply: power supply for DAC
-- clocks: handle to fclk
-- clock-names: "fck"
-
-Optional nodes:
-- Video port for VENC output
-
-VENC Endpoint required properties:
-- ti,invert-polarity: invert the polarity of the video signal
-- ti,channels: 1 for composite, 2 for s-video
-
-
-DSI
----
-
-Required properties:
-- compatible: "ti,omap4-dsi"
-- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
-- reg-names: "proto", "phy", "pll"
-- interrupts: the DSI interrupt line
-- ti,hwmods: "dss_dsi1" or "dss_dsi2"
-- vdd-supply: power supply for DSI
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-Optional nodes:
-- Video port for DSI output
-- DSI controlled peripherals
-
-DSI Endpoint required properties:
-- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
-  DATA1+, DATA1-, ...
-
-
-HDMI
-----
-
-Required properties:
-- compatible: "ti,omap4-hdmi"
-- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
-       'core'
-- reg-names: "wp", "pll", "phy", "core"
-- interrupts: the HDMI interrupt line
-- ti,hwmods: "dss_hdmi"
-- vdda-supply: vdda power supply
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-Optional nodes:
-- Video port for HDMI output
-
-HDMI Endpoint optional properties:
-- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
-  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/video/ti,omap5-dss.txt b/Documentation/devicetree/bindings/video/ti,omap5-dss.txt
deleted file mode 100644 (file)
index 38ffc8f..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-Texas Instruments OMAP5 Display Subsystem
-=========================================
-
-See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
-description about OMAP Display Subsystem bindings.
-
-DSS Core
---------
-
-Required properties:
-- compatible: "ti,omap5-dss"
-- reg: address and length of the register space
-- ti,hwmods: "dss_core"
-- clocks: handle to fclk
-- clock-names: "fck"
-
-Required nodes:
-- DISPC
-
-Optional nodes:
-- DSS Submodules: RFBI, DSI, HDMI
-- Video port for DPI output
-
-DPI Endpoint required properties:
-- data-lines: number of lines used
-
-
-DISPC
------
-
-Required properties:
-- compatible: "ti,omap5-dispc"
-- reg: address and length of the register space
-- ti,hwmods: "dss_dispc"
-- interrupts: the DISPC interrupt
-- clocks: handle to fclk
-- clock-names: "fck"
-
-
-RFBI
-----
-
-Required properties:
-- compatible: "ti,omap5-rfbi"
-- reg: address and length of the register space
-- ti,hwmods: "dss_rfbi"
-- clocks: handles to fclk and iclk
-- clock-names: "fck", "ick"
-
-Optional nodes:
-- Video port for RFBI output
-- RFBI controlled peripherals
-
-
-DSI
----
-
-Required properties:
-- compatible: "ti,omap5-dsi"
-- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
-- reg-names: "proto", "phy", "pll"
-- interrupts: the DSI interrupt line
-- ti,hwmods: "dss_dsi1" or "dss_dsi2"
-- vdd-supply: power supply for DSI
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-Optional nodes:
-- Video port for DSI output
-- DSI controlled peripherals
-
-DSI Endpoint required properties:
-- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
-  DATA1+, DATA1-, ...
-
-
-HDMI
-----
-
-Required properties:
-- compatible: "ti,omap5-hdmi"
-- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
-       'core'
-- reg-names: "wp", "pll", "phy", "core"
-- interrupts: the HDMI interrupt line
-- ti,hwmods: "dss_hdmi"
-- vdda-supply: vdda power supply
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
-
-Optional nodes:
-- Video port for HDMI output
-
-HDMI Endpoint optional properties:
-- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
-  D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
diff --git a/Documentation/devicetree/bindings/video/ti,opa362.txt b/Documentation/devicetree/bindings/video/ti,opa362.txt
deleted file mode 100644 (file)
index f96083c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-OPA362 analog video amplifier
-
-Required properties:
-- compatible: "ti,opa362"
-- enable-gpios: enable/disable output gpio
-
-Required node:
-- Video port 0 for opa362 input
-- Video port 1 for opa362 output
-
-Example:
-
-tv_amp: opa362 {
-       compatible = "ti,opa362";
-       enable-gpios = <&gpio1 23 0>;  /* GPIO to enable video out amplifier */
-
-       ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-                       opa_in: endpoint@0 {
-                               remote-endpoint = <&venc_out>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-                       opa_out: endpoint@0 {
-                               remote-endpoint = <&tv_connector_in>;
-                       };
-               };
-       };
-};
-
-
-
diff --git a/Documentation/devicetree/bindings/video/ti,tfp410.txt b/Documentation/devicetree/bindings/video/ti,tfp410.txt
deleted file mode 100644 (file)
index 2cbe32a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-TFP410 DPI to DVI encoder
-=========================
-
-Required properties:
-- compatible: "ti,tfp410"
-
-Optional properties:
-- powerdown-gpios: power-down gpio
-
-Required nodes:
-- Video port 0 for DPI input
-- Video port 1 for DVI output
-
-Example
--------
-
-tfp410: encoder@0 {
-       compatible = "ti,tfp410";
-       powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>;
-
-       ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-
-                       tfp410_in: endpoint@0 {
-                               remote-endpoint = <&dpi_out>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       tfp410_out: endpoint@0 {
-                               remote-endpoint = <&dvi_connector_in>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/ti,tpd12s015.txt b/Documentation/devicetree/bindings/video/ti,tpd12s015.txt
deleted file mode 100644 (file)
index 26e6d32..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-TPD12S015 HDMI level shifter and ESD protection chip
-====================================================
-
-Required properties:
-- compatible: "ti,tpd12s015"
-
-Optional properties:
-- gpios: CT CP HPD, LS OE and HPD gpios
-
-Required nodes:
-- Video port 0 for HDMI input
-- Video port 1 for HDMI output
-
-Example
--------
-
-tpd12s015: encoder@1 {
-       compatible = "ti,tpd12s015";
-
-       gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
-               <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
-               <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
-
-       ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-
-                       tpd12s015_in: endpoint@0 {
-                               remote-endpoint = <&hdmi_out>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       tpd12s015_out: endpoint@0 {
-                               remote-endpoint = <&hdmi_connector_in>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt b/Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt
deleted file mode 100644 (file)
index 7175dc3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Toppoly TD028TTEC1 Panel
-========================
-
-Required properties:
-- compatible: "toppoly,td028ttec1"
-
-Optional properties:
-- label: a symbolic name for the panel
-
-Required nodes:
-- Video port for DPI input
-
-Example
--------
-
-lcd-panel: td028ttec1@0 {
-       compatible = "toppoly,td028ttec1";
-       reg = <0>;
-       spi-max-frequency = <100000>;
-       spi-cpol;
-       spi-cpha;
-
-       label = "lcd";
-       port {
-               lcd_in: endpoint {
-                       remote-endpoint = <&dpi_out>;
-               };
-       };
-};
-
diff --git a/Documentation/devicetree/bindings/video/tpo,td043mtea1.txt b/Documentation/devicetree/bindings/video/tpo,td043mtea1.txt
deleted file mode 100644 (file)
index ec6d629..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-TPO TD043MTEA1 Panel
-====================
-
-Required properties:
-- compatible: "tpo,td043mtea1"
-- reset-gpios: panel reset gpio
-
-Optional properties:
-- label: a symbolic name for the panel
-
-Required nodes:
-- Video port for DPI input
-
-Example
--------
-
-lcd-panel: panel@0 {
-       compatible = "tpo,td043mtea1";
-       reg = <0>;
-       spi-max-frequency = <100000>;
-       spi-cpol;
-       spi-cpha;
-
-       label = "lcd";
-
-       reset-gpios = <&gpio7 7 0>;
-
-       port {
-               lcd_in: endpoint {
-                       remote-endpoint = <&dpi_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/vga-connector.txt b/Documentation/devicetree/bindings/video/vga-connector.txt
deleted file mode 100644 (file)
index c727f29..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-VGA Connector
-=============
-
-Required properties:
-
-- compatible: "vga-connector"
-
-Optional properties:
-
-- label: a symbolic name for the connector corresponding to a hardware label
-- ddc-i2c-bus: phandle to the I2C bus that is connected to VGA DDC
-
-Required nodes:
-
-The VGA connector internal connections are modeled using the OF graph bindings
-specified in Documentation/devicetree/bindings/graph.txt.
-
-The VGA connector has a single port that must be connected to a video source
-port.
-
-
-Example
--------
-
-vga0: connector@0 {
-       compatible = "vga-connector";
-       label = "vga";
-
-       ddc-i2c-bus = <&i2c3>;
-
-       port {
-               vga_connector_in: endpoint {
-                       remote-endpoint = <&adv7123_out>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt
deleted file mode 100644 (file)
index 2871e21..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-VIA VT8500 Framebuffer
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-fb"
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : framebuffer controller interrupt
-- bits-per-pixel : bit depth of framebuffer (16 or 32)
-
-Required subnodes:
-- display-timings: see display-timing.txt for information
-
-Example:
-
-       fb@d8050800 {
-               compatible = "via,vt8500-fb";
-               reg = <0xd800e400 0x400>;
-               interrupts = <12>;
-               bits-per-pixel = <16>;
-
-               display-timings {
-                       native-mode = <&timing0>;
-                       timing0: 800x480 {
-                               clock-frequency = <0>; /* unused but required */
-                               hactive = <800>;
-                               vactive = <480>;
-                               hfront-porch = <40>;
-                               hback-porch = <88>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                       };
-               };
-       };
-
diff --git a/Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt b/Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt
deleted file mode 100644 (file)
index a850fa0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-VIA/Wondermedia Graphics Engine Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "wm,prizm-ge-rops"
-- reg : Should contain 1 register ranges(address and length)
-
-Example:
-
-       ge_rops@d8050400 {
-               compatible = "wm,prizm-ge-rops";
-               reg = <0xd8050400 0x100>;
-       };
diff --git a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
deleted file mode 100644 (file)
index 0bcadb2..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Wondermedia WM8505 Framebuffer
------------------------------------------------------
-
-Required properties:
-- compatible : "wm,wm8505-fb"
-- reg : Should contain 1 register ranges(address and length)
-- bits-per-pixel : bit depth of framebuffer (16 or 32)
-
-Required subnodes:
-- display-timings: see display-timing.txt for information
-
-Example:
-
-       fb@d8051700 {
-               compatible = "wm,wm8505-fb";
-               reg = <0xd8051700 0x200>;
-               bits-per-pixel = <16>;
-
-               display-timings {
-                       native-mode = <&timing0>;
-                       timing0: 800x480 {
-                               clock-frequency = <0>; /* unused but required */
-                               hactive = <800>;
-                               vactive = <480>;
-                               hfront-porch = <40>;
-                               hback-porch = <88>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/x86/interrupt.txt b/Documentation/devicetree/bindings/x86/interrupt.txt
deleted file mode 100644 (file)
index 7d19f49..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Interrupt chips
----------------
-
-* Intel I/O Advanced Programmable Interrupt Controller (IO APIC)
-
-  Required properties:
-  --------------------
-     compatible = "intel,ce4100-ioapic";
-     #interrupt-cells = <2>;
-
-  Device's interrupt property:
-
-     interrupts = <P S>;
-
-  The first number (P) represents the interrupt pin which is wired to the
-  IO APIC. The second number (S) represents the sense of interrupt which
-  should be configured and can be one of:
-    0 - Edge Rising
-    1 - Level Low
-    2 - Level High
-    3 - Edge Falling
-
-* Local APIC
-  Required property:
-
-     compatible = "intel,ce4100-lapic";
index 5737e3590adb6a338d6165332fa1eff93a07d57e..46a74f0c551a1b5a1ada3dc7e3ae248df1edbbff 100644 (file)
@@ -9,8 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
 and by triggering on falling and rising edges, the turn direction can
 be determined.
 
-Some encoders have both outputs low in stable states, whereas others also have
-a stable state with both outputs high (half-period mode).
+Some encoders have both outputs low in stable states, others also have
+a stable state with both outputs high (half-period mode) and some have
+a stable state in all steps (quarter-period mode).
 
 The phase diagram of these two outputs look like this:
 
@@ -32,6 +33,9 @@ The phase diagram of these two outputs look like this:
                 |<-->|
                  one step (half-period mode)
 
+                |<>|
+                 one step (quarter-period mode)
+
 For more information, please see
        https://en.wikipedia.org/wiki/Rotary_encoder
 
@@ -109,6 +113,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
        .inverted_a     = 0,
        .inverted_b     = 0,
        .half_period    = false,
+       .wakeup_source  = false,
 };
 
 static struct platform_device rotary_encoder_device = {
diff --git a/Documentation/input/userio.txt b/Documentation/input/userio.txt
new file mode 100644 (file)
index 0000000..0880c0f
--- /dev/null
@@ -0,0 +1,70 @@
+                             The userio Protocol
+            (c) 2015 Stephen Chandler Paul <thatslyude@gmail.com>
+                             Sponsored by Red Hat
+--------------------------------------------------------------------------------
+
+1. Introduction
+~~~~~~~~~~~~~~~
+  This module is intended to try to make the lives of input driver developers
+easier by allowing them to test various serio devices (mainly the various
+touchpads found on laptops) without having to have the physical device in front
+of them. userio accomplishes this by allowing any privileged userspace program
+to directly interact with the kernel's serio driver and control a virtual serio
+port from there.
+
+2. Usage overview
+~~~~~~~~~~~~~~~~~
+  In order to interact with the userio kernel module, one simply opens the
+/dev/userio character device in their applications. Commands are sent to the
+kernel module by writing to the device, and any data received from the serio
+driver is read as-is from the /dev/userio device. All of the structures and
+macros you need to interact with the device are defined in <linux/userio.h> and
+<linux/serio.h>.
+
+3. Command Structure
+~~~~~~~~~~~~~~~~~~~~
+  The struct used for sending commands to /dev/userio is as follows:
+
+       struct userio_cmd {
+               __u8 type;
+               __u8 data;
+       };
+
+  "type" describes the type of command that is being sent. This can be any one
+of the USERIO_CMD macros defined in <linux/userio.h>. "data" is the argument
+that goes along with the command. In the event that the command doesn't have an
+argument, this field can be left untouched and will be ignored by the kernel.
+Each command should be sent by writing the struct directly to the character
+device. In the event that the command you send is invalid, an error will be
+returned by the character device and a more descriptive error will be printed
+to the kernel log. Only one command can be sent at a time, any additional data
+written to the character device after the initial command will be ignored.
+  To close the virtual serio port, just close /dev/userio.
+
+4. Commands
+~~~~~~~~~~~
+
+4.1 USERIO_CMD_REGISTER
+~~~~~~~~~~~~~~~~~~~~~~~
+  Registers the port with the serio driver and begins transmitting data back and
+forth. Registration can only be performed once a port type is set with
+USERIO_CMD_SET_PORT_TYPE. Has no argument.
+
+4.2 USERIO_CMD_SET_PORT_TYPE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Sets the type of port we're emulating, where "data" is the port type being
+set. Can be any of the macros from <linux/serio.h>. For example: SERIO_8042
+would set the port type to be a normal PS/2 port.
+
+4.3 USERIO_CMD_SEND_INTERRUPT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Sends an interrupt through the virtual serio port to the serio driver, where
+"data" is the interrupt data being sent.
+
+5. Userspace tools
+~~~~~~~~~~~~~~~~~~
+  The userio userspace tools are able to record PS/2 devices using some of the
+debugging information from i8042, and play back the devices on /dev/userio. The
+latest version of these tools can be found at:
+
+       https://github.com/Lyude/ps2emu
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
deleted file mode 100644 (file)
index de8efbc..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-Notes on Universal Interface for Intel High Definition Audio Codec
-------------------------------------------------------------------
-
-Takashi Iwai <tiwai@suse.de>
-
-
-[Still a draft version]
-
-
-General
-=======
-
-The snd-hda-codec module supports the generic access function for the
-High Definition (HD) audio codecs.  It's designed to be independent
-from the controller code like ac97 codec module.  The real accessors
-from/to the controller must be implemented in the lowlevel driver.
-
-The structure of this module is similar with ac97_codec module.
-Each codec chip belongs to a bus class which communicates with the
-controller.
-
-
-Initialization of Bus Instance
-==============================
-
-The card driver has to create struct hda_bus at first.  The template
-struct should be filled and passed to the constructor:
-
-struct hda_bus_template {
-       void *private_data;
-       struct pci_dev *pci;
-       const char *modelname;
-       struct hda_bus_ops ops;
-};
-
-The card driver can set and use the private_data field to retrieve its
-own data in callback functions.  The pci field is used when the patch
-needs to check the PCI subsystem IDs, so on.  For non-PCI system, it
-doesn't have to be set, of course.
-The modelname field specifies the board's specific configuration.  The
-string is passed to the codec parser, and it depends on the parser how
-the string is used.
-These fields, private_data, pci and modelname are all optional.
-
-The ops field contains the callback functions as the following:
-
-struct hda_bus_ops {
-       int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
-                      unsigned int verb, unsigned int parm);
-       unsigned int (*get_response)(struct hda_codec *codec);
-       void (*private_free)(struct hda_bus *);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       void (*pm_notify)(struct hda_codec *codec);
-#endif
-};
-
-The command callback is called when the codec module needs to send a
-VERB to the controller.  It's always a single command.
-The get_response callback is called when the codec requires the answer
-for the last command.  These two callbacks are mandatory and have to
-be given.
-The third, private_free callback, is optional.  It's called in the
-destructor to release any necessary data in the lowlevel driver.
-
-The pm_notify callback is available only with
-CONFIG_SND_HDA_POWER_SAVE kconfig.  It's called when the codec needs
-to power up or may power down.  The controller should check the all
-belonging codecs on the bus whether they are actually powered off
-(check codec->power_on), and optionally the driver may power down the
-controller side, too.
-
-The bus instance is created via snd_hda_bus_new().  You need to pass
-the card instance, the template, and the pointer to store the
-resultant bus instance.
-
-int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
-                   struct hda_bus **busp);
-
-It returns zero if successful.  A negative return value means any
-error during creation.
-
-
-Creation of Codec Instance
-==========================
-
-Each codec chip on the board is then created on the BUS instance.
-To create a codec instance, call snd_hda_codec_new().
-
-int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-                     struct hda_codec **codecp);
-
-The first argument is the BUS instance, the second argument is the
-address of the codec, and the last one is the pointer to store the
-resultant codec instance (can be NULL if not needed).
-
-The codec is stored in a linked list of bus instance.  You can follow
-the codec list like:
-
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               ...
-       }
-
-The codec isn't initialized at this stage properly.  The
-initialization sequence is called when the controls are built later.
-
-
-Codec Access
-============
-
-To access codec, use snd_hda_codec_read() and snd_hda_codec_write().
-snd_hda_param_read() is for reading parameters.
-For writing a sequence of verbs, use snd_hda_sequence_write().
-
-There are variants of cached read/write, snd_hda_codec_write_cache(),
-snd_hda_sequence_write_cache().  These are used for recording the
-register states for the power-management resume.  When no PM is needed,
-these are equivalent with non-cached version.
-
-To retrieve the number of sub nodes connected to the given node, use
-snd_hda_get_sub_nodes().  The connection list can be obtained via
-snd_hda_get_connections() call.
-
-When an unsolicited event happens, pass the event via
-snd_hda_queue_unsol_event() so that the codec routines will process it
-later.
-
-
-(Mixer) Controls
-================
-
-To create mixer controls of all codecs, call
-snd_hda_build_controls().  It then builds the mixers and does
-initialization stuff on each codec.
-
-
-PCM Stuff
-=========
-
-snd_hda_build_pcms() gives the necessary information to create PCM
-streams.  When it's called, each codec belonging to the bus stores 
-codec->num_pcms and codec->pcm_info fields.  The num_pcms indicates
-the number of elements in pcm_info array.  The card driver is supposed
-to traverse the codec linked list, read the pcm information in
-pcm_info array, and build pcm instances according to them. 
-
-The pcm_info array contains the following record:
-
-/* PCM information for each substream */
-struct hda_pcm_stream {
-       unsigned int substreams;        /* number of substreams, 0 = not exist */
-       unsigned int channels_min;      /* min. number of channels */
-       unsigned int channels_max;      /* max. number of channels */
-       hda_nid_t nid;  /* default NID to query rates/formats/bps, or set up */
-       u32 rates;      /* supported rates */
-       u64 formats;    /* supported formats (SNDRV_PCM_FMTBIT_) */
-       unsigned int maxbps;    /* supported max. bit per sample */
-       struct hda_pcm_ops ops;
-};
-
-/* for PCM creation */
-struct hda_pcm {
-       char *name;
-       struct hda_pcm_stream stream[2];
-};
-
-The name can be passed to snd_pcm_new().  The stream field contains
-the information  for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and
-capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions.  The card driver
-should pass substreams to snd_pcm_new() for the number of substreams
-to create.
-
-The channels_min, channels_max, rates and formats should be copied to
-runtime->hw record.  They and maxbps fields are used also to compute
-the format value for the HDA codec and controller.  Call
-snd_hda_calc_stream_format() to get the format value.
-
-The ops field contains the following callback functions:
-
-struct hda_pcm_ops {
-       int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                   struct snd_pcm_substream *substream);
-       int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                    struct snd_pcm_substream *substream);
-       int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                      unsigned int stream_tag, unsigned int format,
-                      struct snd_pcm_substream *substream);
-       int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
-                      struct snd_pcm_substream *substream);
-};
-
-All are non-NULL, so you can call them safely without NULL check.
-
-The open callback should be called in PCM open after runtime->hw is
-set up.  It may override some setting and constraints additionally.
-Similarly, the close callback should be called in the PCM close.
-
-The prepare callback should be called in PCM prepare.  This will set
-up the codec chip properly for the operation.  The cleanup should be
-called in hw_free to clean up the configuration.
-
-The caller should check the return value, at least for open and
-prepare callbacks.  When a negative value is returned, some error
-occurred.
-
-
-Proc Files
-==========
-
-Each codec dumps the widget node information in
-/proc/asound/card*/codec#* file.  This information would be really
-helpful for debugging.  Please provide its contents together with the
-bug report.
-
-
-Power Management
-================
-
-It's simple:
-Call snd_hda_suspend() in the PM suspend callback.
-Call snd_hda_resume() in the PM resume callback.
-
-
-Codec Preset (Patch)
-====================
-
-To set up and handle the codec functionality fully, each codec may
-have a codec preset (patch).  It's defined in struct hda_codec_preset:
-
-       struct hda_codec_preset {
-               unsigned int id;
-               unsigned int mask;
-               unsigned int subs;
-               unsigned int subs_mask;
-               unsigned int rev;
-               const char *name;
-               int (*patch)(struct hda_codec *codec);
-       };
-
-When the codec id and codec subsystem id match with the given id and
-subs fields bitwise (with bitmask mask and subs_mask), the callback
-patch is called.  The patch callback should initialize the codec and
-set the codec->patch_ops field.  This is defined as below:
-
-       struct hda_codec_ops {
-               int (*build_controls)(struct hda_codec *codec);
-               int (*build_pcms)(struct hda_codec *codec);
-               int (*init)(struct hda_codec *codec);
-               void (*free)(struct hda_codec *codec);
-               void (*unsol_event)(struct hda_codec *codec, unsigned int res);
-       #ifdef CONFIG_PM
-               int (*suspend)(struct hda_codec *codec, pm_message_t state);
-               int (*resume)(struct hda_codec *codec);
-       #endif
-       #ifdef CONFIG_SND_HDA_POWER_SAVE
-               int (*check_power_status)(struct hda_codec *codec,
-                                         hda_nid_t nid);
-       #endif
-       };
-
-The build_controls callback is called from snd_hda_build_controls().
-Similarly, the build_pcms callback is called from
-snd_hda_build_pcms().  The init callback is called after
-build_controls to initialize the hardware.
-The free callback is called as a destructor.
-
-The unsol_event callback is called when an unsolicited event is
-received.
-
-The suspend and resume callbacks are for power management.
-They can be NULL if no special sequence is required.  When the resume
-callback is NULL, the driver calls the init callback and resumes the
-registers from the cache.  If other handling is needed, you'd need to
-write your own resume callback.  There, the amp values can be resumed
-via
-       void snd_hda_codec_resume_amp(struct hda_codec *codec);
-and the other codec registers via
-       void snd_hda_codec_resume_cache(struct hda_codec *codec);
-
-The check_power_status callback is called when the amp value of the
-given widget NID is changed.  The codec code can turn on/off the power
-appropriately from this information.
-
-Each entry can be NULL if not necessary to be called.
-
-
-Generic Parser
-==============
-
-When the device doesn't match with any given presets, the widgets are
-parsed via th generic parser (hda_generic.c).  Its support is
-limited: no multi-channel support, for example.
-
-
-Digital I/O
-===========
-
-Call snd_hda_create_spdif_out_ctls() from the patch to create controls
-related with SPDIF out.
-
-
-Helper Functions
-================
-
-snd_hda_get_codec_name() stores the codec name on the given string.
-
-snd_hda_check_board_config() can be used to obtain the configuration
-information matching with the device.  Define the model string table
-and the table with struct snd_pci_quirk entries (zero-terminated),
-and pass it to the function.  The function checks the modelname given
-as a module parameter, and PCI subsystem IDs.  If the matching entry
-is found, it returns the config field value.
-
-snd_hda_add_new_ctls() can be used to create and add control entries.
-Pass the zero-terminated array of struct snd_kcontrol_new
-
-Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be
-used for the entry of struct snd_kcontrol_new.
-
-The input MUX helper callbacks for such a control are provided, too:
-snd_hda_input_mux_info() and snd_hda_input_mux_put().  See
-patch_realtek.c for example.
index 75d25a1d6e42e7ba96677a40b336b2091e489b2e..c010be8c85d7668547459badcc964e822b494e30 100644 (file)
@@ -288,6 +288,24 @@ prev_pid == 0
 # cat sched_wakeup/filter
 common_pid == 0
 
+5.4 PID filtering
+-----------------
+
+The set_event_pid file in the same directory as the top events directory
+exists, will filter all events from tracing any task that does not have the
+PID listed in the set_event_pid file.
+
+# cd /sys/kernel/debug/tracing
+# echo $$ > set_event_pid
+# echo 1 > events/enabled
+
+Will only trace events for the current task.
+
+To add more PIDs without losing the PIDs already included, use '>>'.
+
+# echo 123 244 1 >> set_event_pid
+
+
 6. Event triggers
 =================
 
index ef621d34ba5bf7a5a3c2d570de2ebaecf0615cc0..f52f297cb40627a7d5855f04399977f304272e51 100644 (file)
@@ -204,6 +204,12 @@ of ftrace. Here is a list of some of the key files:
 
        Have the function tracer only trace a single thread.
 
+  set_event_pid:
+
+       Have the events only trace a task with a PID listed in this file.
+       Note, sched_switch and sched_wake_up will also trace events
+       listed in this file.
+
   set_graph_function:
 
        Set a "trigger" function where tracing should start
@@ -2437,6 +2443,23 @@ The following commands are supported:
 
    echo '!writeback*:mod:ext3' >> set_ftrace_filter
 
+  Mod command supports module globbing. Disable tracing for all
+  functions except a specific module:
+
+   echo '!*:mod:!ext3' >> set_ftrace_filter
+
+  Disable tracing for all modules, but still trace kernel:
+
+   echo '!*:mod:*' >> set_ftrace_filter
+
+  Enable filter only for kernel:
+
+   echo '*write*:mod:!*' >> set_ftrace_filter
+
+  Enable filter for module globbing:
+
+   echo '*write*:mod:*snd*' >> set_ftrace_filter
+
 - traceon/traceoff
   These commands turn tracing on and off when the specified
   functions are hit. The parameter determines how many times the
index eabf3d35a49d8ff4600baf91df165417a6e3d28d..7af7f4a01f0b83224b50f3a7f52eac58cc751b3e 100644 (file)
@@ -2757,9 +2757,10 @@ S:       Supported
 F:     drivers/net/ethernet/cisco/enic/
 
 CISCO VIC LOW LATENCY NIC DRIVER
-M:     Upinder Malhi <umalhi@cisco.com>
+M:     Christian Benvenuti <benve@cisco.com>
+M:     Dave Goodell <dgoodell@cisco.com>
 S:     Supported
-F:     drivers/infiniband/hw/usnic
+F:     drivers/infiniband/hw/usnic/
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
 M:     Hartley Sweeten <hsweeten@visionengravers.com>
@@ -3403,6 +3404,7 @@ M:        Support Opensource <support.opensource@diasemi.com>
 W:     http://www.dialog-semiconductor.com/products
 S:     Supported
 F:     Documentation/hwmon/da90??
+F:     Documentation/devicetree/bindings/sound/da[79]*.txt
 F:     drivers/gpio/gpio-da90??.c
 F:     drivers/hwmon/da90??-hwmon.c
 F:     drivers/iio/adc/da91??-*.c
@@ -3615,7 +3617,7 @@ S:        Maintained
 F:     drivers/gpu/drm/drm_panel.c
 F:     drivers/gpu/drm/panel/
 F:     include/drm/drm_panel.h
-F:     Documentation/devicetree/bindings/panel/
+F:     Documentation/devicetree/bindings/display/panel/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@intel.com>
@@ -3654,15 +3656,15 @@ M:      Alison Wang <alison.wang@freescale.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/fsl-dcu/
-F:     Documentation/devicetree/bindings/video/fsl,dcu.txt
-F:     Documentation/devicetree/bindings/panel/nec,nl4827hc19_05b.txt
+F:     Documentation/devicetree/bindings/display/fsl,dcu.txt
+F:     Documentation/devicetree/bindings/display/panel/nec,nl4827hc19_05b.txt
 
 DRM DRIVERS FOR FREESCALE IMX
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 F:     drivers/gpu/drm/imx/
-F:     Documentation/devicetree/bindings/drm/imx/
+F:     Documentation/devicetree/bindings/display/imx/
 
 DRM DRIVERS FOR GMA500 (Poulsbo, Moorestown and derivative chipsets)
 M:     Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
@@ -3683,7 +3685,7 @@ F:        drivers/gpu/drm/tegra/
 F:     drivers/gpu/host1x/
 F:     include/linux/host1x.h
 F:     include/uapi/drm/tegra_drm.h
-F:     Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
 
 DRM DRIVERS FOR RENESAS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -3700,7 +3702,7 @@ M:        Mark Yao <mark.yao@rock-chips.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 F:     drivers/gpu/drm/rockchip/
-F:     Documentation/devicetree/bindings/video/rockchip*
+F:     Documentation/devicetree/bindings/display/rockchip*
 
 DRM DRIVERS FOR STI
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
@@ -3709,7 +3711,7 @@ L:        dri-devel@lists.freedesktop.org
 T:     git http://git.linaro.org/people/benjamin.gaignard/kernel.git
 S:     Maintained
 F:     drivers/gpu/drm/sti
-F:     Documentation/devicetree/bindings/gpu/st,stih4xx.txt
+F:     Documentation/devicetree/bindings/display/st,stih4xx.txt
 
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
@@ -4405,7 +4407,6 @@ Q:        http://patchwork.kernel.org/project/linux-fbdev/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev.git
 S:     Maintained
 F:     Documentation/fb/
-F:     Documentation/devicetree/bindings/fb/
 F:     drivers/video/
 F:     include/video/
 F:     include/linux/fb.h
@@ -6969,6 +6970,7 @@ S:        Supported
 F:     arch/metag/
 F:     Documentation/metag/
 F:     Documentation/devicetree/bindings/metag/
+F:     Documentation/devicetree/bindings/interrupt-controller/img,*
 F:     drivers/clocksource/metag_generic.c
 F:     drivers/irqchip/irq-metag.c
 F:     drivers/irqchip/irq-metag-ext.c
@@ -8066,6 +8068,14 @@ F:       include/linux/pci*
 F:     arch/x86/pci/
 F:     arch/x86/kernel/quirks.c
 
+PCI DRIVER FOR ALTERA PCIE IP
+M:     Ley Foon Tan <lftan@altera.com>
+L:     rfi@lists.rocketboards.org (moderated for non-subscribers)
+L:     linux-pci@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/altera-pcie.txt
+F:     drivers/pci/host/pcie-altera.c
+
 PCI DRIVER FOR ARM VERSATILE PLATFORM
 M:     Rob Herring <robh@kernel.org>
 L:     linux-pci@vger.kernel.org
@@ -8167,6 +8177,14 @@ L:       linux-pci@vger.kernel.org
 S:     Maintained
 F:     drivers/pci/host/*spear*
 
+PCI MSI DRIVER FOR ALTERA MSI IP
+M:     Ley Foon Tan <lftan@altera.com>
+L:     rfi@lists.rocketboards.org (moderated for non-subscribers)
+L:     linux-pci@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
+F:     drivers/pci/host/pcie-altera-msi.c
+
 PCI MSI DRIVER FOR APPLIEDMICRO XGENE
 M:     Duc Dang <dhdang@apm.com>
 L:     linux-pci@vger.kernel.org
@@ -8175,6 +8193,13 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
 F:     drivers/pci/host/pci-xgene-msi.c
 
+PCIE DRIVER FOR HISILICON
+M:     Zhou Wang <wangzhou1@hisilicon.com>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
+F:     drivers/pci/host/pcie-hisi.c
+
 PCMCIA SUBSYSTEM
 P:     Linux PCMCIA Team
 L:     linux-pcmcia@lists.infradead.org
@@ -9614,7 +9639,7 @@ SIMPLEFB FB DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/video/simple-framebuffer.txt
+F:     Documentation/devicetree/bindings/display/simple-framebuffer.txt
 F:     drivers/video/fbdev/simplefb.c
 F:     include/linux/platform_data/simplefb.h
 
@@ -10245,6 +10270,7 @@ L:      linux-snps-arc@lists.infraded.org
 S:     Supported
 F:     arch/arc/
 F:     Documentation/devicetree/bindings/arc/*
+F:     Documentation/devicetree/bindings/interrupt-controller/snps,arc*
 F:     drivers/tty/serial/arc_uart.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
 
@@ -11250,6 +11276,12 @@ S:     Maintained
 F:     Documentation/fb/uvesafb.txt
 F:     drivers/video/fbdev/uvesafb.*
 
+VF610 NAND DRIVER
+M:     Stefan Agner <stefan@agner.ch>
+L:     linux-mtd@lists.infradead.org
+S:     Supported
+F:     drivers/mtd/nand/vf610_nfc.c
+
 VFAT/FAT/MSDOS FILESYSTEM
 M:     OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
 S:     Maintained
@@ -11280,6 +11312,12 @@ S:     Maintained
 F:     drivers/media/v4l2-core/videobuf2-*
 F:     include/media/videobuf2-*
 
+VIRTUAL SERIO DEVICE DRIVER
+M:     Stephen Chandler Paul <thatslyude@gmail.com>
+S:     Maintained
+F:     drivers/input/serio/userio.c
+F:     include/uapi/linux/userio.h
+
 VIRTIO CONSOLE DRIVER
 M:     Amit Shah <amit.shah@redhat.com>
 L:     virtualization@lists.linux-foundation.org
index 8a27a48304a4c0127d97996d73c7d7dc0515d8a3..cf0cf34eeb24b14ef070735e83d25b0f7f6aecec 100644 (file)
@@ -121,7 +121,7 @@ $(boot_targets): vmlinux
        $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
 
 dtbs: scripts
-       $(Q)$(MAKE) $(build)=$(boot)/dts dtbs
+       $(Q)$(MAKE) $(build)=$(boot)/dts
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
index b0e3f19bbd07e32cb57c91f803302603ebe429fc..a09f11b71e663d59f5f636339c0fb24704563b34 100644 (file)
@@ -6,10 +6,12 @@ ifneq ($(CONFIG_ARC_BUILTIN_DTB_NAME),"")
 endif
 
 obj-y   += $(builtindtb-y).dtb.o
-targets += $(builtindtb-y).dtb
+dtb-y := $(builtindtb-y).dtb
 
 .SECONDARY: $(obj)/$(builtindtb-y).dtb.S
 
-dtbs:  $(addprefix  $(obj)/, $(builtindtb-y).dtb)
+dtstree                := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
 
+always := $(dtb-y)
 clean-files := *.dtb  *.dtb.S
index bb8fa023d5741dff9b4f9033ed2cf6f6d7b69f2d..6019f5d3ad7f7314c5664f41b6100fef556a6f49 100644 (file)
@@ -740,5 +740,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
 dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
 endif
 
+dtstree                := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
 always         := $(dtb-y)
 clean-files    := *.dtb
index 7da7c2da4af13b3bc711f15a9098c10da80d56fa..0bb36e9af93623e6f3a6e4ee96ae64ce8c215e53 100644 (file)
 
                reg = <0x38>;
                interrupt-parent = <&gpio0>;
-               interrupts = <31 0>;
+               interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
 
                reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
 
index a5b27c85a91c8b14464feabd30d2af7ec03b9d8c..4ea89344a5fff51115160fad9e34b16a4a4377eb 100644 (file)
@@ -13,6 +13,7 @@
 /dts-v1/;
 #include "imx28.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 
 / {
        model = "Ka-Ro electronics TX28 module";
                pinctrl-names = "default";
                pinctrl-0 = <&tx28_edt_ft5x06_pins>;
                interrupt-parent = <&gpio2>;
-               interrupts = <5 0>;
+               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
                reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
                wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>;
        };
index 3b73e81dc3f0df58507a7a6a3ae0556f9abee7dd..13e842b0c7857b1050c73319842113d6bf08dbb3 100644 (file)
@@ -12,6 +12,7 @@
 /dts-v1/;
 #include "imx53-tx53.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pwm/pwm.h>
 
 / {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_edt_ft5x06_1>;
                interrupt-parent = <&gpio6>;
-               interrupts = <15 0>;
+               interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
                reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
                wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
        };
index da08de324e9eb595db45c7cae308327d77bd33a9..13cb7ccfea44dd653e8100669d415b88699c7831 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pwm/pwm.h>
 
 / {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_edt_ft5x06>;
                interrupt-parent = <&gpio6>;
-               interrupts = <15 0>;
+               interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
                reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
                wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
                linux,wakeup;
index 482b7aa37808ef78d68ce886f0b527774951b428..36ae9160b558cadfab86810dc84db4d5cec35695 100644 (file)
@@ -22,8 +22,6 @@
        charger: bci {
                compatible = "ti,twl4030-bci";
                interrupts = <9>, <2>;
-               io-channels = <&twl4030_madc 11>;
-               io-channel-name = "vac";
                bci3v1-supply = <&vusb3v1>;
        };
 
index be648eb47cd9d80cbecc09a8144a8423a82f7907..bd425302c97a3ec9966d4c04bdb61c3c40252056 100644 (file)
@@ -14,6 +14,7 @@ generic-y += local.h
 generic-y += local64.h
 generic-y += mm-arch-hooks.h
 generic-y += msgbuf.h
+generic-y += msi.h
 generic-y += param.h
 generic-y += parport.h
 generic-y += poll.h
index 8857d2869a5f8cb0d76a8efb021d3bd2304fe3e1..0070e8520cd447932ece57098d091c511ed1b895 100644 (file)
@@ -52,12 +52,6 @@ struct pci_sys_data {
        u8              (*swizzle)(struct pci_dev *, u8 *);
                                        /* IRQ mapping                          */
        int             (*map_irq)(const struct pci_dev *, u8, u8);
-                                       /* Resource alignement requirements     */
-       resource_size_t (*align_resource)(struct pci_dev *dev,
-                                         const struct resource *res,
-                                         resource_size_t start,
-                                         resource_size_t size,
-                                         resource_size_t align);
        void            *private_data;  /* platform controller private data     */
 };
 
index 874e1823f8036fd9915c63e8b95561e96c0152b7..6551d28c27e687068bc69af093a9a97805362d46 100644 (file)
 #include <asm/mach/pci.h>
 
 static int debug_pci;
+static resource_size_t (*align_resource)(struct pci_dev *dev,
+                 const struct resource *res,
+                 resource_size_t start,
+                 resource_size_t size,
+                 resource_size_t align) = NULL;
 
 /*
  * We can't use pci_get_device() here since we are
@@ -456,7 +461,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                sys->busnr   = busnr;
                sys->swizzle = hw->swizzle;
                sys->map_irq = hw->map_irq;
-               sys->align_resource = hw->align_resource;
+               align_resource = hw->align_resource;
                INIT_LIST_HEAD(&sys->resources);
 
                if (hw->private_data)
@@ -572,7 +577,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
                                resource_size_t size, resource_size_t align)
 {
        struct pci_dev *dev = data;
-       struct pci_sys_data *sys = dev->sysdata;
        resource_size_t start = res->start;
 
        if (res->flags & IORESOURCE_IO && start & 0x300)
@@ -580,8 +584,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 
        start = (start + align - 1) & ~(align - 1);
 
-       if (sys->align_resource)
-               return sys->align_resource(dev, res, start, size, align);
+       if (align_resource)
+               return align_resource(dev, res, start, size, align);
 
        return start;
 }
index d9f88330e7b0a033ed64e93a715ec47504cda523..b01ec43d1ca9b4e80775d5336d8841600852c3a4 100644 (file)
@@ -14,3 +14,9 @@ dts-dirs += sprd
 dts-dirs += xilinx
 
 subdir-y       := $(dts-dirs)
+
+dtstree                := $(srctree)/$(src)
+
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(foreach d,$(dts-dirs), $(wildcard $(dtstree)/$(d)/*.dts)))
+
+always         := $(dtb-y)
index 564a3f7df71d76992c04e210b40077a3f4adda69..128fa942f09e9f5adccf6ac214f0e10510ca2015 100644 (file)
@@ -14,7 +14,6 @@
 
        chosen {
                stdout-path = &serial0;
-               linux,pci-probe-only;
        };
 };
 
index 0abaf1ad830eeab6db9f9bebed4f8f3784831d66..6c08467c6a3ab56e9c3b6a323421f7fd2b706317 100644 (file)
@@ -8,5 +8,8 @@ dtb-$(CONFIG_H8300H_SIM) := h8300h_sim.dtb
 dtb-$(CONFIG_H8S_SIM) := h8s_sim.dtb
 dtb-$(CONFIG_H8S_EDOSK2674) := edosk2674.dtb
 
+dtstree                := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
 always     := $(dtb-y)
 clean-files := *.dtb.S *.dtb
index 9739857bdedcb89fe6847d26fdef70041a70228d..033a58214119535488836cd805ff17ce6567cc3d 100644 (file)
@@ -72,7 +72,7 @@ $(boot_targets): vmlinux
        $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
 
 dtbs: scripts
-       $(Q)$(MAKE) $(build)=$(boot)/dts dtbs
+       $(Q)$(MAKE) $(build)=$(boot)/dts
 
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
index 72c12187942606316950775222df89e332b885b0..097c6da4547fb2d1b8896e31d28a3b230912a47b 100644 (file)
@@ -12,11 +12,10 @@ endif
 dtb-$(CONFIG_METAG_BUILTIN_DTB)        += $(builtindtb-y).dtb
 obj-$(CONFIG_METAG_BUILTIN_DTB)        += $(builtindtb-y).dtb.o
 
-targets        += dtbs
-targets        += $(dtb-y)
+dtstree                := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
 
 .SECONDARY: $(obj)/$(builtindtb-y).dtb.S
 
-dtbs: $(addprefix $(obj)/, $(dtb-y))
-
+always += $(dtb-y)
 clean-files += *.dtb *.dtb.S
index 778a34028c1b1fb6b67754053e24ea09828eee31..bac7b8dab9a4907db6733da6e66a6a85fe89a92d 100644 (file)
@@ -9,6 +9,9 @@ dts-dirs        += ralink
 
 obj-y          := $(addsuffix /, $(dts-dirs))
 
+dtstree                := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(foreach d,$(dts-dirs), $(wildcard $(dtstree)/$(d)/*.dts)))
+
 always         := $(dtb-y)
 subdir-y       := $(dts-dirs)
 clean-files    := *.dtb *.dtb.S
index 9e524c26db14591b78a108d4274cef49d7862f1b..36df46eaba24900549e394fc6cd94ec55bad8588 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/of.h>
+#include <linux/of_pci.h>
 #include <linux/kexec.h>
 
 #include <asm/mmu.h>
@@ -495,18 +496,7 @@ static void __init find_and_init_phbs(void)
         * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
         * in chosen.
         */
-       if (of_chosen) {
-               const int *prop;
-
-               prop = of_get_property(of_chosen,
-                               "linux,pci-probe-only", NULL);
-               if (prop) {
-                       if (*prop)
-                               pci_add_flags(PCI_PROBE_ONLY);
-                       else
-                               pci_clear_flags(PCI_PROBE_ONLY);
-               }
-       }
+       of_pci_check_probe_only();
 }
 
 static void __init pSeries_setup_arch(void)
index 2685ea03b0642bf7a653b52e09b5966d037df49f..6bc134bd7ec265555bdd6442775c285c38f2d5ab 100644 (file)
@@ -27,8 +27,6 @@ static struct regulator_consumer_supply dummy_supplies[] = {
        REGULATOR_SUPPLY("vdd33a", "smsc911x"),
 };
 
-static const char *part_probes[] = { "cmdlinepart", NULL };
-
 static struct mtd_partition rsk_partitions[] = {
        {
                .name           = "Bootloader",
@@ -50,7 +48,6 @@ static struct physmap_flash_data flash_data = {
        .parts                  = rsk_partitions,
        .nr_parts               = ARRAY_SIZE(rsk_partitions),
        .width                  = 2,
-       .part_probe_types       = part_probes,
 };
 
 static struct resource flash_resource = {
index b91d7f1461758ba759413042c1529faf4196912b..badf0951d73c8f2d875aa5cbc093caef04616aeb 100644 (file)
@@ -185,8 +185,10 @@ static unsigned long pci_parse_of_flags(u32 addr0)
 
        if (addr0 & 0x02000000) {
                flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
-               flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
                flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
+               if (addr0 & 0x01000000)
+                       flags |= IORESOURCE_MEM_64
+                                | PCI_BASE_ADDRESS_MEM_TYPE_64;
                if (addr0 & 0x40000000)
                        flags |= IORESOURCE_PREFETCH
                                 | PCI_BASE_ADDRESS_MEM_PREFETCH;
@@ -655,6 +657,9 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
                                pbm->io_space.start);
        pci_add_resource_offset(&resources, &pbm->mem_space,
                                pbm->mem_space.start);
+       if (pbm->mem64_space.flags)
+               pci_add_resource_offset(&resources, &pbm->mem64_space,
+                                       pbm->mem_space.start);
        pbm->busn.start = pbm->pci_first_busno;
        pbm->busn.end   = pbm->pci_last_busno;
        pbm->busn.flags = IORESOURCE_BUS;
index 944a06536ecc129ab81c9e758a6f89b92d3091fe..33524c1d5328b051172e52faf8751bf0d33d5333 100644 (file)
@@ -406,6 +406,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
        }
 
        num_pbm_ranges = i / sizeof(*pbm_ranges);
+       memset(&pbm->mem64_space, 0, sizeof(struct resource));
 
        for (i = 0; i < num_pbm_ranges; i++) {
                const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
@@ -451,7 +452,12 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
                        break;
 
                case 3:
-                       /* XXX 64-bit MEM handling XXX */
+                       /* 64-bit MEM handling */
+                       pbm->mem64_space.start = a;
+                       pbm->mem64_space.end = a + size - 1UL;
+                       pbm->mem64_space.flags = IORESOURCE_MEM;
+                       saw_mem = 1;
+                       break;
 
                default:
                        break;
@@ -465,15 +471,22 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
                prom_halt();
        }
 
-       printk("%s: PCI IO[%llx] MEM[%llx]\n",
+       printk("%s: PCI IO[%llx] MEM[%llx]",
               pbm->name,
               pbm->io_space.start,
               pbm->mem_space.start);
+       if (pbm->mem64_space.flags)
+               printk(" MEM64[%llx]",
+                      pbm->mem64_space.start);
+       printk("\n");
 
        pbm->io_space.name = pbm->mem_space.name = pbm->name;
+       pbm->mem64_space.name = pbm->name;
 
        request_resource(&ioport_resource, &pbm->io_space);
        request_resource(&iomem_resource, &pbm->mem_space);
+       if (pbm->mem64_space.flags)
+               request_resource(&iomem_resource, &pbm->mem64_space);
 
        pci_register_legacy_regions(&pbm->io_space,
                                    &pbm->mem_space);
index 75803c780af3605681991c74271d941015a3dbd1..37222ca849df48df46ed45927686ef487f6f49bb 100644 (file)
@@ -97,6 +97,7 @@ struct pci_pbm_info {
        /* PBM I/O and Memory space resources. */
        struct resource                 io_space;
        struct resource                 mem_space;
+       struct resource                 mem64_space;
        struct resource                 busn;
 
        /* Base of PCI Config space, can be per-PBM or shared. */
index 8b7b0a51e742cd26defe12b535f37a865ee3c172..311bcf338f07e75a48115ef4edf3df5f748b6940 100644 (file)
@@ -556,6 +556,7 @@ void ftrace_replace_code(int enable)
        run_sync();
 
        report = "updating code";
+       count = 0;
 
        for_ftrace_rec_iter(iter) {
                rec = ftrace_rec_iter_record(iter);
@@ -563,11 +564,13 @@ void ftrace_replace_code(int enable)
                ret = add_update(rec, enable);
                if (ret)
                        goto remove_breakpoints;
+               count++;
        }
 
        run_sync();
 
        report = "removing breakpoints";
+       count = 0;
 
        for_ftrace_rec_iter(iter) {
                rec = ftrace_rec_iter_record(iter);
@@ -575,6 +578,7 @@ void ftrace_replace_code(int enable)
                ret = finish_update(rec, enable);
                if (ret)
                        goto remove_breakpoints;
+               count++;
        }
 
        run_sync();
index ff3c3101d003f214b21c15cd7482c6b2d0cb3a44..d1d35ccffed3cab7b6caa791b91f237210183907 100644 (file)
@@ -42,7 +42,6 @@ int klp_write_module_reloc(struct module *mod, unsigned long type,
        bool readonly;
        unsigned long val;
        unsigned long core = (unsigned long)mod->module_core;
-       unsigned long core_ro_size = mod->core_ro_size;
        unsigned long core_size = mod->core_size;
 
        switch (type) {
@@ -70,10 +69,12 @@ int klp_write_module_reloc(struct module *mod, unsigned long type,
                /* loc does not point to any symbol inside the module */
                return -EINVAL;
 
-       if (loc < core + core_ro_size)
+       readonly = false;
+
+#ifdef CONFIG_DEBUG_SET_MODULE_RONX
+       if (loc < core + mod->core_ro_size)
                readonly = true;
-       else
-               readonly = false;
+#endif
 
        /* determine if the relocation spans a page boundary */
        numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2;
index dc78a4a9a46663f10600afd013d9230fe5fe222b..eccd4d99e6a4a7182bf74469f5ecd580e8f22417 100644 (file)
@@ -675,6 +675,14 @@ int pcibios_add_device(struct pci_dev *dev)
 
 int pcibios_alloc_irq(struct pci_dev *dev)
 {
+       /*
+        * If the PCI device was already claimed by core code and has
+        * MSI enabled, probing of the pcibios IRQ will overwrite
+        * dev->irq.  So bail out if MSI is already enabled.
+        */
+       if (pci_dev_msi_enabled(dev))
+               return -EBUSY;
+
        return pcibios_enable_irq(dev);
 }
 
index 5b662c0faf8c2e1848d15d4dced105db9988c7c8..ea6f3802c17b73e8c622c53f68d2414eeb482f98 100644 (file)
@@ -54,7 +54,7 @@ void pcibios_scan_specific_bus(int busn)
 }
 EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
 
-int __init pci_subsys_init(void)
+static int __init pci_subsys_init(void)
 {
        /*
         * The init function returns an non zero value when
index f9e6a068aafd3ca3c296a9bee832dbd74bdb99ab..709b5748a2d7ed44aeacf7d378cc99b4e37c0939 100644 (file)
@@ -101,6 +101,10 @@ zImage: vmlinux
 %.dtb:
        $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
 
+dtbs: scripts
+       $(Q)$(MAKE) $(build)=$(boot)/dts
+
 define archhelp
   @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
+  @echo '  dtbs        - Build device tree blobs for enabled boards'
 endef
index 5f711bba830790c49d54c9fd926f0bf128dae01f..a15e241c9153c4791fe89977e03775c824e3acc1 100644 (file)
@@ -12,4 +12,9 @@ ifneq ($(CONFIG_BUILTIN_DTB),"")
 obj-$(CONFIG_OF) += $(BUILTIN_DTB)
 endif
 
-clean-files := *.dtb.S
+dtstree := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
+always += $(dtb-y)
+clean-files += *.dtb *.dtb.S
+
index bc18aa213bb1c9ce23d07cc60b54f505d7d14c81..6e26761a27dae90d0671b1edf38b2e8533d56df3 100644 (file)
@@ -27,7 +27,7 @@
  * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
  * irrelevant.
  */
-#include <asm-generic/io-64-nonatomic-hi-lo.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 
 static bool force_enable_dimms;
 module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
index 3935745ac78bf83e2299172fef06f342a038b65a..32d684af0ec7c8a36781e5b7e712c7dd0e65b241 100644 (file)
@@ -43,7 +43,7 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #include "internal.h"
 
index 6e810881e48b09f0615250c8f2ca2dfdbb47c44e..71059e32bebc989e180bee874372f24582ba10b9 100644 (file)
@@ -406,7 +406,7 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
  *
  * Note, you will need to drop the reference with put_device() after use.
  *
- * @fn is allowed to do anything including calling back into class
+ * @match is allowed to do anything including calling back into class
  * code.  There's no locking restriction.
  */
 struct device *class_find_device(struct class *class, struct device *start,
index 3dc53a16ed3aaf14dfd30311c16e0dc14f6623a0..9462d27528507d693d8e4efe0e6464597ab1768b 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/string.h>
 #include <linux/drbd.h>
 #include <linux/slab.h>
-#include <asm/kmap_types.h>
+#include <linux/highmem.h>
 
 #include "drbd_int.h"
 
index 5959c2981cc7d18efbbec56615db1d29b2698064..2f477d45d6cfa42d586080db8c293d41406055ae 100644 (file)
@@ -2803,8 +2803,7 @@ out_new_dev:
 out_mem2:
        put_disk(disk);
 out_mem:
-       if (pd->rb_pool)
-               mempool_destroy(pd->rb_pool);
+       mempool_destroy(pd->rb_pool);
        kfree(pd);
 out_mutex:
        mutex_unlock(&ctl_mutex);
index 8d2a7728434d05cd06250e2c6fb2d74a3336bc88..ca5c71ab4b4d04b8e47fbeefdbc6fc698d4e99f5 100644 (file)
@@ -36,8 +36,6 @@
 #include <crypto/algapi.h>
 #include <crypto/des.h>
 
-#include <asm/kmap_types.h>
-
 //#define HIFN_DEBUG
 
 #ifdef HIFN_DEBUG
index 4ad062b0ef26141c203934eb1e3ce2d49dcc396c..1f453382258a9993b577df8b46671917ad2f1b5f 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/io.h>
 #include "edac_core.h"
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #define I3200_REVISION        "1.1"
 
index a981dc6fd88e09eb42f46bf33c34e54eb699383f..18d77ace4813cedadb8a635344b4ed0113f690c5 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/pci_ids.h>
 #include <linux/edac.h>
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include "edac_core.h"
 
 #define IE31200_REVISION "1.0"
index 7c5cdc62f31c35902e8c20d8af7c1c4bea431de1..314cf5cf268ce80ab6d9aad480e9ba7aa6f0fccf 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/pci_ids.h>
 #include <linux/edac.h>
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include "edac_core.h"
 
 #define X38_REVISION           "1.1"
index b8dd847443c50750429a0d2a4b00407351490fd7..6ea8df6c73970f5c41503b3266fad675b40f99d6 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
-#include <asm-generic/bug.h>
+#include <linux/bug.h>
 
 enum mxc_gpio_hwtype {
        IMX1_GPIO,      /* runs on i.mx1 */
index ab37d1121be8277728bff5d25a0cb4a4599de0aa..990f656e6ab051eda034dd2cf24045de7813cd36 100644 (file)
@@ -832,6 +832,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        mutex_init(&dev_priv->sb_lock);
        mutex_init(&dev_priv->modeset_restore_lock);
        mutex_init(&dev_priv->csr_lock);
+       mutex_init(&dev_priv->av_mutex);
 
        intel_pm_setup(dev);
 
index e1db8de52851b979c31607abf7b6995bd1febe0b..22dd7043c9efb428120406d2aa5f73d025dc97dd 100644 (file)
@@ -1885,6 +1885,11 @@ struct drm_i915_private {
        /* hda/i915 audio component */
        struct i915_audio_component *audio_component;
        bool audio_component_registered;
+       /**
+        * av_mutex - mutex for audio/video sync
+        *
+        */
+       struct mutex av_mutex;
 
        uint32_t hw_context_size;
        struct list_head context_list;
index 2a5c76faf9f8dbc19ec6d17c490ff833d61d6afd..ae8df0a43de68a154685d84001f29f31b66a463c 100644 (file)
@@ -68,6 +68,31 @@ static const struct {
        { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
 };
 
+/* HDMI N/CTS table */
+#define TMDS_297M 297000
+#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
+static const struct {
+       int sample_rate;
+       int clock;
+       int n;
+       int cts;
+} aud_ncts[] = {
+       { 44100, TMDS_296M, 4459, 234375 },
+       { 44100, TMDS_297M, 4704, 247500 },
+       { 48000, TMDS_296M, 5824, 281250 },
+       { 48000, TMDS_297M, 5120, 247500 },
+       { 32000, TMDS_296M, 5824, 421875 },
+       { 32000, TMDS_297M, 3072, 222750 },
+       { 88200, TMDS_296M, 8918, 234375 },
+       { 88200, TMDS_297M, 9408, 247500 },
+       { 96000, TMDS_296M, 11648, 281250 },
+       { 96000, TMDS_297M, 10240, 247500 },
+       { 176400, TMDS_296M, 17836, 234375 },
+       { 176400, TMDS_297M, 18816, 247500 },
+       { 192000, TMDS_296M, 23296, 281250 },
+       { 192000, TMDS_297M, 20480, 247500 },
+};
+
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
 static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
 {
@@ -90,6 +115,45 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
        return hdmi_audio_clock[i].config;
 }
 
+static int audio_config_get_n(const struct drm_display_mode *mode, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) {
+               if ((rate == aud_ncts[i].sample_rate) &&
+                       (mode->clock == aud_ncts[i].clock)) {
+                       return aud_ncts[i].n;
+               }
+       }
+       return 0;
+}
+
+static uint32_t audio_config_setup_n_reg(int n, uint32_t val)
+{
+       int n_low, n_up;
+       uint32_t tmp = val;
+
+       n_low = n & 0xfff;
+       n_up = (n >> 12) & 0xff;
+       tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK);
+       tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) |
+                       (n_low << AUD_CONFIG_LOWER_N_SHIFT) |
+                       AUD_CONFIG_N_PROG_ENABLE);
+       return tmp;
+}
+
+/* check whether N/CTS/M need be set manually */
+static bool audio_rate_need_prog(struct intel_crtc *crtc,
+                                const struct drm_display_mode *mode)
+{
+       if (((mode->clock == TMDS_297M) ||
+                (mode->clock == TMDS_296M)) &&
+               intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
+               return true;
+       else
+               return false;
+}
+
 static bool intel_eld_uptodate(struct drm_connector *connector,
                               int reg_eldv, uint32_t bits_eldv,
                               int reg_elda, uint32_t bits_elda,
@@ -184,6 +248,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
 
        DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe));
 
+       mutex_lock(&dev_priv->av_mutex);
+
        /* Disable timestamps */
        tmp = I915_READ(HSW_AUD_CFG(pipe));
        tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
@@ -199,6 +265,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
        tmp &= ~AUDIO_ELD_VALID(pipe);
        tmp &= ~AUDIO_OUTPUT_ENABLE(pipe);
        I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
 }
 
 static void hsw_audio_codec_enable(struct drm_connector *connector,
@@ -208,13 +276,20 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        enum pipe pipe = intel_crtc->pipe;
+       struct i915_audio_component *acomp = dev_priv->audio_component;
        const uint8_t *eld = connector->eld;
+       struct intel_digital_port *intel_dig_port =
+               enc_to_dig_port(&encoder->base);
+       enum port port = intel_dig_port->port;
        uint32_t tmp;
        int len, i;
+       int n, rate;
 
        DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n",
                      pipe_name(pipe), drm_eld_size(eld));
 
+       mutex_lock(&dev_priv->av_mutex);
+
        /* Enable audio presence detect, invalidate ELD */
        tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
        tmp |= AUDIO_OUTPUT_ENABLE(pipe);
@@ -246,13 +321,32 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
        /* Enable timestamps */
        tmp = I915_READ(HSW_AUD_CFG(pipe));
        tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
-       tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
        tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
        if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
                tmp |= AUD_CONFIG_N_VALUE_INDEX;
        else
                tmp |= audio_config_hdmi_pixel_clock(mode);
+
+       tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+       if (audio_rate_need_prog(intel_crtc, mode)) {
+               if (!acomp)
+                       rate = 0;
+               else if (port >= PORT_A && port <= PORT_E)
+                       rate = acomp->aud_sample_rate[port];
+               else {
+                       DRM_ERROR("invalid port: %d\n", port);
+                       rate = 0;
+               }
+               n = audio_config_get_n(mode, rate);
+               if (n != 0)
+                       tmp = audio_config_setup_n_reg(n, tmp);
+               else
+                       DRM_DEBUG_KMS("no suitable N value is found\n");
+       }
+
        I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
 }
 
 static void ilk_audio_codec_disable(struct intel_encoder *encoder)
@@ -527,12 +621,91 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
        return ret;
 }
 
+static int i915_audio_component_sync_audio_rate(struct device *dev,
+                                               int port, int rate)
+{
+       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_device *drm_dev = dev_priv->dev;
+       struct intel_encoder *intel_encoder;
+       struct intel_digital_port *intel_dig_port;
+       struct intel_crtc *crtc;
+       struct drm_display_mode *mode;
+       struct i915_audio_component *acomp = dev_priv->audio_component;
+       enum pipe pipe = -1;
+       u32 tmp;
+       int n;
+
+       /* HSW, BDW SKL need this fix */
+       if (!IS_SKYLAKE(dev_priv) &&
+               !IS_BROADWELL(dev_priv) &&
+               !IS_HASWELL(dev_priv))
+               return 0;
+
+       mutex_lock(&dev_priv->av_mutex);
+       /* 1. get the pipe */
+       for_each_intel_encoder(drm_dev, intel_encoder) {
+               if (intel_encoder->type != INTEL_OUTPUT_HDMI)
+                       continue;
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               if (port == intel_dig_port->port) {
+                       crtc = to_intel_crtc(intel_encoder->base.crtc);
+                       if (!crtc) {
+                               DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__);
+                               continue;
+                       }
+                       pipe = crtc->pipe;
+                       break;
+               }
+       }
+
+       if (pipe == INVALID_PIPE) {
+               DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
+               mutex_unlock(&dev_priv->av_mutex);
+               return -ENODEV;
+       }
+       DRM_DEBUG_KMS("pipe %c connects port %c\n",
+                                 pipe_name(pipe), port_name(port));
+       mode = &crtc->config->base.adjusted_mode;
+
+       /* port must be valid now, otherwise the pipe will be invalid */
+       acomp->aud_sample_rate[port] = rate;
+
+       /* 2. check whether to set the N/CTS/M manually or not */
+       if (!audio_rate_need_prog(crtc, mode)) {
+               tmp = I915_READ(HSW_AUD_CFG(pipe));
+               tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+               I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+               mutex_unlock(&dev_priv->av_mutex);
+               return 0;
+       }
+
+       n = audio_config_get_n(mode, rate);
+       if (n == 0) {
+               DRM_DEBUG_KMS("Using automatic mode for N value on port %c\n",
+                                         port_name(port));
+               tmp = I915_READ(HSW_AUD_CFG(pipe));
+               tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
+               I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+               mutex_unlock(&dev_priv->av_mutex);
+               return 0;
+       }
+
+       /* 3. set the N/CTS/M */
+       tmp = I915_READ(HSW_AUD_CFG(pipe));
+       tmp = audio_config_setup_n_reg(n, tmp);
+       I915_WRITE(HSW_AUD_CFG(pipe), tmp);
+
+       mutex_unlock(&dev_priv->av_mutex);
+       return 0;
+}
+
 static const struct i915_audio_component_ops i915_audio_component_ops = {
        .owner          = THIS_MODULE,
        .get_power      = i915_audio_component_get_power,
        .put_power      = i915_audio_component_put_power,
        .codec_wake_override = i915_audio_component_codec_wake_override,
        .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
+       .sync_audio_rate = i915_audio_component_sync_audio_rate,
 };
 
 static int i915_audio_component_bind(struct device *i915_dev,
@@ -540,6 +713,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
 {
        struct i915_audio_component *acomp = data;
        struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
+       int i;
 
        if (WARN_ON(acomp->ops || acomp->dev))
                return -EEXIST;
@@ -547,6 +721,9 @@ static int i915_audio_component_bind(struct device *i915_dev,
        drm_modeset_lock_all(dev_priv->dev);
        acomp->ops = &i915_audio_component_ops;
        acomp->dev = i915_dev;
+       BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
+       for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
+               acomp->aud_sample_rate[i] = 0;
        dev_priv->audio_component = acomp;
        drm_modeset_unlock_all(dev_priv->dev);
 
index 6ab51ae3c39d5753f5315fd7451db737a311a24e..513a16cc6e18536e1e38e23bf2068b99bb65f197 100644 (file)
@@ -171,6 +171,16 @@ config HID_CHICONY
        ---help---
        Support for Chicony Tactical pad.
 
+config HID_CORSAIR
+       tristate "Corsair devices"
+       depends on HID && USB && LEDS_CLASS
+       ---help---
+       Support for Corsair devices that are not fully compliant with the
+       HID standard.
+
+       Supported devices:
+       - Vengeance K90
+
 config HID_PRODIKEYS
        tristate "Prodikeys PC-MIDI Keyboard support"
        depends on HID && SND
@@ -257,6 +267,12 @@ config HID_GEMBIRD
        ---help---
        Support for Gembird JPD-DualForce 2.
 
+config HID_GFRM
+       tristate "Google Fiber TV Box remote control support"
+       depends on HID
+       ---help---
+       Support for Google Fiber TV Box remote controls
+
 config HID_HOLTEK
        tristate "Holtek HID devices"
        depends on USB_HID
@@ -672,9 +688,8 @@ config HID_SAITEK
 
        Supported devices:
        - PS1000 Dual Analog Pad
-       - R.A.T.9 Gaming Mouse
-       - R.A.T.7 Gaming Mouse
-       - M.M.O.7 Gaming Mouse
+       - Saitek R.A.T.7, R.A.T.9, M.M.O.7 Gaming Mice
+       - Mad Catz R.A.T.5, R.A.T.9 Gaming Mice
 
 config HID_SAMSUNG
        tristate "Samsung InfraRed remote control or keyboards"
index e6441bc7dae42b9c415a00e25d61d977af475866..00011fee08b98f80fb032244041a1e3e7c45cb44 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_HID_BELKIN)      += hid-belkin.o
 obj-$(CONFIG_HID_BETOP_FF)     += hid-betopff.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
+obj-$(CONFIG_HID_CORSAIR)      += hid-corsair.o
 obj-$(CONFIG_HID_CP2112)       += hid-cp2112.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
 obj-$(CONFIG_HID_DRAGONRISE)   += hid-dr.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_HID_ELECOM)      += hid-elecom.o
 obj-$(CONFIG_HID_ELO)          += hid-elo.o
 obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
 obj-$(CONFIG_HID_GEMBIRD)      += hid-gembird.o
+obj-$(CONFIG_HID_GFRM)         += hid-gfrm.o
 obj-$(CONFIG_HID_GT683R)       += hid-gt683r.o
 obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
 obj-$(CONFIG_HID_HOLTEK)       += hid-holtek-kbd.o
index 0e6a42d37eb6f374ef864f383fc23d15bf844736..07cbc70f00e7dfc8ddbfc7554f8e9c134721bc1f 100644 (file)
@@ -256,7 +256,7 @@ out:
        return 0;
 }
 
-static void appleir_input_configured(struct hid_device *hid,
+static int appleir_input_configured(struct hid_device *hid,
                struct hid_input *hidinput)
 {
        struct input_dev *input_dev = hidinput->input;
@@ -275,6 +275,8 @@ static void appleir_input_configured(struct hid_device *hid,
        for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
                set_bit(appleir->keymap[i], input_dev->keybit);
        clear_bit(KEY_RESERVED, input_dev->keybit);
+
+       return 0;
 }
 
 static int appleir_input_mapping(struct hid_device *hid,
index 340ba9d394a09045949c0adc26dc4839c589a65f..3280aff28e907dfc910fbafcfbb00316ccf2a13b 100644 (file)
@@ -23,7 +23,8 @@ static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
                dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
                rdesc[53] = 0x65;
-       } return rdesc;
+       }
+       return rdesc;
 }
 
 static const struct hid_device_id aureal_devices[] = {
index 70a11ac3811926733826129674e292bc907202f1..c6f7a694f67a189daaae4be80645fb8773bfd2d5 100644 (file)
@@ -725,6 +725,7 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
 
        if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
            (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
+            hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
             hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
             hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
             hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
@@ -1611,7 +1612,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                "Multi-Axis Controller"
        };
        const char *type, *bus;
-       char buf[64];
+       char buf[64] = "";
        unsigned int i;
        int len;
        int ret;
@@ -1678,6 +1679,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
        case BUS_BLUETOOTH:
                bus = "BLUETOOTH";
                break;
+       case BUS_I2C:
+               bus = "I2C";
+               break;
        default:
                bus = "<UNKNOWN>";
        }
@@ -1828,6 +1832,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
@@ -1896,6 +1901,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
@@ -1928,6 +1934,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
@@ -1981,6 +1988,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
 #endif
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
new file mode 100644 (file)
index 0000000..bcefb9e
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * HID driver for Corsair devices
+ *
+ * Supported devices:
+ *  - Vengeance K90 Keyboard
+ *
+ * Copyright (c) 2015 Clement Vuchener
+ */
+
+/*
+ * 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/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/leds.h>
+
+#include "hid-ids.h"
+
+#define CORSAIR_USE_K90_MACRO  (1<<0)
+#define CORSAIR_USE_K90_BACKLIGHT      (1<<1)
+
+struct k90_led {
+       struct led_classdev cdev;
+       int brightness;
+       struct work_struct work;
+       bool removed;
+};
+
+struct k90_drvdata {
+       struct k90_led record_led;
+};
+
+struct corsair_drvdata {
+       unsigned long quirks;
+       struct k90_drvdata *k90;
+       struct k90_led *backlight;
+};
+
+#define K90_GKEY_COUNT 18
+
+static int corsair_usage_to_gkey(unsigned int usage)
+{
+       /* G1 (0xd0) to G16 (0xdf) */
+       if (usage >= 0xd0 && usage <= 0xdf)
+               return usage - 0xd0 + 1;
+       /* G17 (0xe8) to G18 (0xe9) */
+       if (usage >= 0xe8 && usage <= 0xe9)
+               return usage - 0xe8 + 17;
+       return 0;
+}
+
+static unsigned short corsair_gkey_map[K90_GKEY_COUNT] = {
+       BTN_TRIGGER_HAPPY1,
+       BTN_TRIGGER_HAPPY2,
+       BTN_TRIGGER_HAPPY3,
+       BTN_TRIGGER_HAPPY4,
+       BTN_TRIGGER_HAPPY5,
+       BTN_TRIGGER_HAPPY6,
+       BTN_TRIGGER_HAPPY7,
+       BTN_TRIGGER_HAPPY8,
+       BTN_TRIGGER_HAPPY9,
+       BTN_TRIGGER_HAPPY10,
+       BTN_TRIGGER_HAPPY11,
+       BTN_TRIGGER_HAPPY12,
+       BTN_TRIGGER_HAPPY13,
+       BTN_TRIGGER_HAPPY14,
+       BTN_TRIGGER_HAPPY15,
+       BTN_TRIGGER_HAPPY16,
+       BTN_TRIGGER_HAPPY17,
+       BTN_TRIGGER_HAPPY18,
+};
+
+module_param_array_named(gkey_codes, corsair_gkey_map, ushort, NULL, S_IRUGO);
+MODULE_PARM_DESC(gkey_codes, "Key codes for the G-keys");
+
+static unsigned short corsair_record_keycodes[2] = {
+       BTN_TRIGGER_HAPPY19,
+       BTN_TRIGGER_HAPPY20
+};
+
+module_param_array_named(recordkey_codes, corsair_record_keycodes, ushort,
+                        NULL, S_IRUGO);
+MODULE_PARM_DESC(recordkey_codes, "Key codes for the MR (start and stop record) button");
+
+static unsigned short corsair_profile_keycodes[3] = {
+       BTN_TRIGGER_HAPPY21,
+       BTN_TRIGGER_HAPPY22,
+       BTN_TRIGGER_HAPPY23
+};
+
+module_param_array_named(profilekey_codes, corsair_profile_keycodes, ushort,
+                        NULL, S_IRUGO);
+MODULE_PARM_DESC(profilekey_codes, "Key codes for the profile buttons");
+
+#define CORSAIR_USAGE_SPECIAL_MIN 0xf0
+#define CORSAIR_USAGE_SPECIAL_MAX 0xff
+
+#define CORSAIR_USAGE_MACRO_RECORD_START 0xf6
+#define CORSAIR_USAGE_MACRO_RECORD_STOP 0xf7
+
+#define CORSAIR_USAGE_PROFILE 0xf1
+#define CORSAIR_USAGE_M1 0xf1
+#define CORSAIR_USAGE_M2 0xf2
+#define CORSAIR_USAGE_M3 0xf3
+#define CORSAIR_USAGE_PROFILE_MAX 0xf3
+
+#define CORSAIR_USAGE_META_OFF 0xf4
+#define CORSAIR_USAGE_META_ON  0xf5
+
+#define CORSAIR_USAGE_LIGHT 0xfa
+#define CORSAIR_USAGE_LIGHT_OFF 0xfa
+#define CORSAIR_USAGE_LIGHT_DIM 0xfb
+#define CORSAIR_USAGE_LIGHT_MEDIUM 0xfc
+#define CORSAIR_USAGE_LIGHT_BRIGHT 0xfd
+#define CORSAIR_USAGE_LIGHT_MAX 0xfd
+
+/* USB control protocol */
+
+#define K90_REQUEST_BRIGHTNESS 49
+#define K90_REQUEST_MACRO_MODE 2
+#define K90_REQUEST_STATUS 4
+#define K90_REQUEST_GET_MODE 5
+#define K90_REQUEST_PROFILE 20
+
+#define K90_MACRO_MODE_SW 0x0030
+#define K90_MACRO_MODE_HW 0x0001
+
+#define K90_MACRO_LED_ON  0x0020
+#define K90_MACRO_LED_OFF 0x0040
+
+/*
+ * LED class devices
+ */
+
+#define K90_BACKLIGHT_LED_SUFFIX "::backlight"
+#define K90_RECORD_LED_SUFFIX "::record"
+
+static enum led_brightness k90_backlight_get(struct led_classdev *led_cdev)
+{
+       int ret;
+       struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
+       struct device *dev = led->cdev.dev->parent;
+       struct usb_interface *usbif = to_usb_interface(dev->parent);
+       struct usb_device *usbdev = interface_to_usbdev(usbif);
+       int brightness;
+       char data[8];
+
+       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+                             K90_REQUEST_STATUS,
+                             USB_DIR_IN | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, 0, 0, data, 8,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret < 0) {
+               dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
+                        ret);
+               return -EIO;
+       }
+       brightness = data[4];
+       if (brightness < 0 || brightness > 3) {
+               dev_warn(dev,
+                        "Read invalid backlight brightness: %02hhx.\n",
+                        data[4]);
+               return -EIO;
+       }
+       return brightness;
+}
+
+static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev)
+{
+       struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
+
+       return led->brightness;
+}
+
+static void k90_brightness_set(struct led_classdev *led_cdev,
+                              enum led_brightness brightness)
+{
+       struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
+
+       led->brightness = brightness;
+       schedule_work(&led->work);
+}
+
+static void k90_backlight_work(struct work_struct *work)
+{
+       int ret;
+       struct k90_led *led = container_of(work, struct k90_led, work);
+       struct device *dev;
+       struct usb_interface *usbif;
+       struct usb_device *usbdev;
+
+       if (led->removed)
+               return;
+
+       dev = led->cdev.dev->parent;
+       usbif = to_usb_interface(dev->parent);
+       usbdev = interface_to_usbdev(usbif);
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
+                             K90_REQUEST_BRIGHTNESS,
+                             USB_DIR_OUT | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, led->brightness, 0,
+                             NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (ret != 0)
+               dev_warn(dev, "Failed to set backlight brightness (error: %d).\n",
+                        ret);
+}
+
+static void k90_record_led_work(struct work_struct *work)
+{
+       int ret;
+       struct k90_led *led = container_of(work, struct k90_led, work);
+       struct device *dev;
+       struct usb_interface *usbif;
+       struct usb_device *usbdev;
+       int value;
+
+       if (led->removed)
+               return;
+
+       dev = led->cdev.dev->parent;
+       usbif = to_usb_interface(dev->parent);
+       usbdev = interface_to_usbdev(usbif);
+
+       if (led->brightness > 0)
+               value = K90_MACRO_LED_ON;
+       else
+               value = K90_MACRO_LED_OFF;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
+                             K90_REQUEST_MACRO_MODE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, value, 0, NULL, 0,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret != 0)
+               dev_warn(dev, "Failed to set record LED state (error: %d).\n",
+                        ret);
+}
+
+/*
+ * Keyboard attributes
+ */
+
+static ssize_t k90_show_macro_mode(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int ret;
+       struct usb_interface *usbif = to_usb_interface(dev->parent);
+       struct usb_device *usbdev = interface_to_usbdev(usbif);
+       const char *macro_mode;
+       char data[8];
+
+       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+                             K90_REQUEST_GET_MODE,
+                             USB_DIR_IN | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, 0, 0, data, 2,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret < 0) {
+               dev_warn(dev, "Failed to get K90 initial mode (error %d).\n",
+                        ret);
+               return -EIO;
+       }
+
+       switch (data[0]) {
+       case K90_MACRO_MODE_HW:
+               macro_mode = "HW";
+               break;
+
+       case K90_MACRO_MODE_SW:
+               macro_mode = "SW";
+               break;
+       default:
+               dev_warn(dev, "K90 in unknown mode: %02hhx.\n",
+                        data[0]);
+               return -EIO;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
+}
+
+static ssize_t k90_store_macro_mode(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       int ret;
+       struct usb_interface *usbif = to_usb_interface(dev->parent);
+       struct usb_device *usbdev = interface_to_usbdev(usbif);
+       __u16 value;
+
+       if (strncmp(buf, "SW", 2) == 0)
+               value = K90_MACRO_MODE_SW;
+       else if (strncmp(buf, "HW", 2) == 0)
+               value = K90_MACRO_MODE_HW;
+       else
+               return -EINVAL;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
+                             K90_REQUEST_MACRO_MODE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, value, 0, NULL, 0,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret != 0) {
+               dev_warn(dev, "Failed to set macro mode.\n");
+               return ret;
+       }
+
+       return count;
+}
+
+static ssize_t k90_show_current_profile(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       int ret;
+       struct usb_interface *usbif = to_usb_interface(dev->parent);
+       struct usb_device *usbdev = interface_to_usbdev(usbif);
+       int current_profile;
+       char data[8];
+
+       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+                             K90_REQUEST_STATUS,
+                             USB_DIR_IN | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, 0, 0, data, 8,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret < 0) {
+               dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
+                        ret);
+               return -EIO;
+       }
+       current_profile = data[7];
+       if (current_profile < 1 || current_profile > 3) {
+               dev_warn(dev, "Read invalid current profile: %02hhx.\n",
+                        data[7]);
+               return -EIO;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
+}
+
+static ssize_t k90_store_current_profile(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       int ret;
+       struct usb_interface *usbif = to_usb_interface(dev->parent);
+       struct usb_device *usbdev = interface_to_usbdev(usbif);
+       int profile;
+
+       if (kstrtoint(buf, 10, &profile))
+               return -EINVAL;
+       if (profile < 1 || profile > 3)
+               return -EINVAL;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
+                             K90_REQUEST_PROFILE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR |
+                             USB_RECIP_DEVICE, profile, 0, NULL, 0,
+                             USB_CTRL_SET_TIMEOUT);
+       if (ret != 0) {
+               dev_warn(dev, "Failed to change current profile (error %d).\n",
+                        ret);
+               return ret;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(macro_mode, 0644, k90_show_macro_mode, k90_store_macro_mode);
+static DEVICE_ATTR(current_profile, 0644, k90_show_current_profile,
+                  k90_store_current_profile);
+
+static struct attribute *k90_attrs[] = {
+       &dev_attr_macro_mode.attr,
+       &dev_attr_current_profile.attr,
+       NULL
+};
+
+static const struct attribute_group k90_attr_group = {
+       .attrs = k90_attrs,
+};
+
+/*
+ * Driver functions
+ */
+
+static int k90_init_backlight(struct hid_device *dev)
+{
+       int ret;
+       struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
+       size_t name_sz;
+       char *name;
+
+       drvdata->backlight = kzalloc(sizeof(struct k90_led), GFP_KERNEL);
+       if (!drvdata->backlight) {
+               ret = -ENOMEM;
+               goto fail_backlight_alloc;
+       }
+
+       name_sz =
+           strlen(dev_name(&dev->dev)) + sizeof(K90_BACKLIGHT_LED_SUFFIX);
+       name = kzalloc(name_sz, GFP_KERNEL);
+       if (!name) {
+               ret = -ENOMEM;
+               goto fail_name_alloc;
+       }
+       snprintf(name, name_sz, "%s" K90_BACKLIGHT_LED_SUFFIX,
+                dev_name(&dev->dev));
+       drvdata->backlight->removed = false;
+       drvdata->backlight->cdev.name = name;
+       drvdata->backlight->cdev.max_brightness = 3;
+       drvdata->backlight->cdev.brightness_set = k90_brightness_set;
+       drvdata->backlight->cdev.brightness_get = k90_backlight_get;
+       INIT_WORK(&drvdata->backlight->work, k90_backlight_work);
+       ret = led_classdev_register(&dev->dev, &drvdata->backlight->cdev);
+       if (ret != 0)
+               goto fail_register_cdev;
+
+       return 0;
+
+fail_register_cdev:
+       kfree(drvdata->backlight->cdev.name);
+fail_name_alloc:
+       kfree(drvdata->backlight);
+       drvdata->backlight = NULL;
+fail_backlight_alloc:
+       return ret;
+}
+
+static int k90_init_macro_functions(struct hid_device *dev)
+{
+       int ret;
+       struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
+       struct k90_drvdata *k90;
+       size_t name_sz;
+       char *name;
+
+       k90 = kzalloc(sizeof(struct k90_drvdata), GFP_KERNEL);
+       if (!k90) {
+               ret = -ENOMEM;
+               goto fail_drvdata;
+       }
+       drvdata->k90 = k90;
+
+       /* Init LED device for record LED */
+       name_sz = strlen(dev_name(&dev->dev)) + sizeof(K90_RECORD_LED_SUFFIX);
+       name = kzalloc(name_sz, GFP_KERNEL);
+       if (!name) {
+               ret = -ENOMEM;
+               goto fail_record_led_alloc;
+       }
+       snprintf(name, name_sz, "%s" K90_RECORD_LED_SUFFIX,
+                dev_name(&dev->dev));
+       k90->record_led.removed = false;
+       k90->record_led.cdev.name = name;
+       k90->record_led.cdev.max_brightness = 1;
+       k90->record_led.cdev.brightness_set = k90_brightness_set;
+       k90->record_led.cdev.brightness_get = k90_record_led_get;
+       INIT_WORK(&k90->record_led.work, k90_record_led_work);
+       k90->record_led.brightness = 0;
+       ret = led_classdev_register(&dev->dev, &k90->record_led.cdev);
+       if (ret != 0)
+               goto fail_record_led;
+
+       /* Init attributes */
+       ret = sysfs_create_group(&dev->dev.kobj, &k90_attr_group);
+       if (ret != 0)
+               goto fail_sysfs;
+
+       return 0;
+
+fail_sysfs:
+       k90->record_led.removed = true;
+       led_classdev_unregister(&k90->record_led.cdev);
+       cancel_work_sync(&k90->record_led.work);
+fail_record_led:
+       kfree(k90->record_led.cdev.name);
+fail_record_led_alloc:
+       kfree(k90);
+fail_drvdata:
+       drvdata->k90 = NULL;
+       return ret;
+}
+
+static void k90_cleanup_backlight(struct hid_device *dev)
+{
+       struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
+
+       if (drvdata->backlight) {
+               drvdata->backlight->removed = true;
+               led_classdev_unregister(&drvdata->backlight->cdev);
+               cancel_work_sync(&drvdata->backlight->work);
+               kfree(drvdata->backlight->cdev.name);
+               kfree(drvdata->backlight);
+       }
+}
+
+static void k90_cleanup_macro_functions(struct hid_device *dev)
+{
+       struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
+       struct k90_drvdata *k90 = drvdata->k90;
+
+       if (k90) {
+               sysfs_remove_group(&dev->dev.kobj, &k90_attr_group);
+
+               k90->record_led.removed = true;
+               led_classdev_unregister(&k90->record_led.cdev);
+               cancel_work_sync(&k90->record_led.work);
+               kfree(k90->record_led.cdev.name);
+
+               kfree(k90);
+       }
+}
+
+static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id)
+{
+       int ret;
+       unsigned long quirks = id->driver_data;
+       struct corsair_drvdata *drvdata;
+       struct usb_interface *usbif = to_usb_interface(dev->dev.parent);
+
+       drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata),
+                              GFP_KERNEL);
+       if (drvdata == NULL)
+               return -ENOMEM;
+       drvdata->quirks = quirks;
+       hid_set_drvdata(dev, drvdata);
+
+       ret = hid_parse(dev);
+       if (ret != 0) {
+               hid_err(dev, "parse failed\n");
+               return ret;
+       }
+       ret = hid_hw_start(dev, HID_CONNECT_DEFAULT);
+       if (ret != 0) {
+               hid_err(dev, "hw start failed\n");
+               return ret;
+       }
+
+       if (usbif->cur_altsetting->desc.bInterfaceNumber == 0) {
+               if (quirks & CORSAIR_USE_K90_MACRO) {
+                       ret = k90_init_macro_functions(dev);
+                       if (ret != 0)
+                               hid_warn(dev, "Failed to initialize K90 macro functions.\n");
+               }
+               if (quirks & CORSAIR_USE_K90_BACKLIGHT) {
+                       ret = k90_init_backlight(dev);
+                       if (ret != 0)
+                               hid_warn(dev, "Failed to initialize K90 backlight.\n");
+               }
+       }
+
+       return 0;
+}
+
+static void corsair_remove(struct hid_device *dev)
+{
+       k90_cleanup_macro_functions(dev);
+       k90_cleanup_backlight(dev);
+
+       hid_hw_stop(dev);
+}
+
+static int corsair_event(struct hid_device *dev, struct hid_field *field,
+                        struct hid_usage *usage, __s32 value)
+{
+       struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
+
+       if (!drvdata->k90)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+       case CORSAIR_USAGE_MACRO_RECORD_START:
+               drvdata->k90->record_led.brightness = 1;
+               break;
+       case CORSAIR_USAGE_MACRO_RECORD_STOP:
+               drvdata->k90->record_led.brightness = 0;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int corsair_input_mapping(struct hid_device *dev,
+                                struct hid_input *input,
+                                struct hid_field *field,
+                                struct hid_usage *usage, unsigned long **bit,
+                                int *max)
+{
+       int gkey;
+
+       gkey = corsair_usage_to_gkey(usage->hid & HID_USAGE);
+       if (gkey != 0) {
+               hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                   corsair_gkey_map[gkey - 1]);
+               return 1;
+       }
+       if ((usage->hid & HID_USAGE) >= CORSAIR_USAGE_SPECIAL_MIN &&
+           (usage->hid & HID_USAGE) <= CORSAIR_USAGE_SPECIAL_MAX) {
+               switch (usage->hid & HID_USAGE) {
+               case CORSAIR_USAGE_MACRO_RECORD_START:
+                       hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                           corsair_record_keycodes[0]);
+                       return 1;
+
+               case CORSAIR_USAGE_MACRO_RECORD_STOP:
+                       hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                           corsair_record_keycodes[1]);
+                       return 1;
+
+               case CORSAIR_USAGE_M1:
+                       hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                           corsair_profile_keycodes[0]);
+                       return 1;
+
+               case CORSAIR_USAGE_M2:
+                       hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                           corsair_profile_keycodes[1]);
+                       return 1;
+
+               case CORSAIR_USAGE_M3:
+                       hid_map_usage_clear(input, usage, bit, max, EV_KEY,
+                                           corsair_profile_keycodes[2]);
+                       return 1;
+
+               default:
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id corsair_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90),
+               .driver_data = CORSAIR_USE_K90_MACRO |
+                              CORSAIR_USE_K90_BACKLIGHT },
+       {}
+};
+
+MODULE_DEVICE_TABLE(hid, corsair_devices);
+
+static struct hid_driver corsair_driver = {
+       .name = "corsair",
+       .id_table = corsair_devices,
+       .probe = corsair_probe,
+       .event = corsair_event,
+       .remove = corsair_remove,
+       .input_mapping = corsair_input_mapping,
+};
+
+static int __init corsair_init(void)
+{
+       return hid_register_driver(&corsair_driver);
+}
+
+static void corsair_exit(void)
+{
+       hid_unregister_driver(&corsair_driver);
+}
+
+module_init(corsair_init);
+module_exit(corsair_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Clement Vuchener");
+MODULE_DESCRIPTION("HID driver for Corsair devices");
index ce0644424f587707e68023f066eefecc50048d6b..1d78ba3b799e6f020eee8f9e16c9cab5b8f61627 100644 (file)
@@ -234,6 +234,58 @@ static __u8 pid0011_rdesc_fixed[] = {
        0xC0                /*  End Collection                  */
 };
 
+static __u8 pid0006_rdesc_fixed[] = {
+       0x05, 0x01,        /* Usage Page (Generic Desktop)      */
+       0x09, 0x04,        /* Usage (Joystick)                  */
+       0xA1, 0x01,        /* Collection (Application)          */
+       0xA1, 0x02,        /*   Collection (Logical)            */
+       0x75, 0x08,        /*     Report Size (8)               */
+       0x95, 0x05,        /*     Report Count (5)              */
+       0x15, 0x00,        /*     Logical Minimum (0)           */
+       0x26, 0xFF, 0x00,  /*     Logical Maximum (255)         */
+       0x35, 0x00,        /*     Physical Minimum (0)          */
+       0x46, 0xFF, 0x00,  /*     Physical Maximum (255)        */
+       0x09, 0x30,        /*     Usage (X)                     */
+       0x09, 0x33,        /*     Usage (Ry)                    */
+       0x09, 0x32,        /*     Usage (Z)                     */
+       0x09, 0x31,        /*     Usage (Y)                     */
+       0x09, 0x34,        /*     Usage (Ry)                    */
+       0x81, 0x02,        /*     Input (Variable)              */
+       0x75, 0x04,        /*     Report Size (4)               */
+       0x95, 0x01,        /*     Report Count (1)              */
+       0x25, 0x07,        /*     Logical Maximum (7)           */
+       0x46, 0x3B, 0x01,  /*     Physical Maximum (315)        */
+       0x65, 0x14,        /*     Unit (Centimeter)             */
+       0x09, 0x39,        /*     Usage (Hat switch)            */
+       0x81, 0x42,        /*     Input (Variable)              */
+       0x65, 0x00,        /*     Unit (None)                   */
+       0x75, 0x01,        /*     Report Size (1)               */
+       0x95, 0x0C,        /*     Report Count (12)             */
+       0x25, 0x01,        /*     Logical Maximum (1)           */
+       0x45, 0x01,        /*     Physical Maximum (1)          */
+       0x05, 0x09,        /*     Usage Page (Button)           */
+       0x19, 0x01,        /*     Usage Minimum (0x01)          */
+       0x29, 0x0C,        /*     Usage Maximum (0x0C)          */
+       0x81, 0x02,        /*     Input (Variable)              */
+       0x06, 0x00, 0xFF,  /*     Usage Page (Vendor Defined)   */
+       0x75, 0x01,        /*     Report Size (1)               */
+       0x95, 0x08,        /*     Report Count (8)              */
+       0x25, 0x01,        /*     Logical Maximum (1)           */
+       0x45, 0x01,        /*     Physical Maximum (1)          */
+       0x09, 0x01,        /*     Usage (0x01)                  */
+       0x81, 0x02,        /*     Input (Variable)              */
+       0xC0,              /*   End Collection                  */
+       0xA1, 0x02,        /*   Collection (Logical)            */
+       0x75, 0x08,        /*     Report Size (8)               */
+       0x95, 0x07,        /*     Report Count (7)              */
+       0x46, 0xFF, 0x00,  /*     Physical Maximum (255)        */
+       0x26, 0xFF, 0x00,  /*     Logical Maximum (255)         */
+       0x09, 0x02,        /*     Usage (0x02)                  */
+       0x91, 0x02,        /*     Output (Variable)             */
+       0xC0,              /*   End Collection                  */
+       0xC0               /* End Collection                    */
+};
+
 static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                                unsigned int *rsize)
 {
@@ -244,6 +296,12 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(pid0011_rdesc_fixed);
                }
                break;
+       case 0x0006:
+               if (*rsize == sizeof(pid0006_rdesc_fixed)) {
+                       rdesc = pid0006_rdesc_fixed;
+                       *rsize = sizeof(pid0006_rdesc_fixed);
+               }
+               break;
        }
        return rdesc;
 }
index d0bd13b62dc2dc542868262a6c38ab6d1c47b8f1..6e3848a8d8dd1416a0091ce0e7d263325dd8910b 100644 (file)
@@ -27,7 +27,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
                rdesc[47] = 0x00;
        }
-    return rdesc;
+       return rdesc;
 }
 
 static const struct hid_device_id elecom_devices[] = {
index 4e49462870abdf2f265c1528ae6c07fa4f783ec8..aad8c162a825dc60516700b1bd8caf8efeec4244 100644 (file)
@@ -37,7 +37,7 @@ static bool use_fw_quirk = true;
 module_param(use_fw_quirk, bool, S_IRUGO);
 MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
 
-static void elo_input_configured(struct hid_device *hdev,
+static int elo_input_configured(struct hid_device *hdev,
                struct hid_input *hidinput)
 {
        struct input_dev *input = hidinput->input;
@@ -45,6 +45,8 @@ static void elo_input_configured(struct hid_device *hdev,
        set_bit(BTN_TOUCH, input->keybit);
        set_bit(ABS_PRESSURE, input->absbit);
        input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
+
+       return 0;
 }
 
 static void elo_process_data(struct input_dev *input, const u8 *data, int size)
diff --git a/drivers/hid/hid-gfrm.c b/drivers/hid/hid-gfrm.c
new file mode 100644 (file)
index 0000000..075b1c0
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * HID driver for Google Fiber TV Box remote controls
+ *
+ * Copyright (c) 2014-2015 Google Inc.
+ *
+ * Author: Petri Gynther <pgynther@google.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/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define GFRM100  1  /* Google Fiber GFRM100 (Bluetooth classic) */
+#define GFRM200  2  /* Google Fiber GFRM200 (Bluetooth LE) */
+
+#define GFRM100_SEARCH_KEY_REPORT_ID   0xF7
+#define GFRM100_SEARCH_KEY_DOWN        0x0
+#define GFRM100_SEARCH_KEY_AUDIO_DATA  0x1
+#define GFRM100_SEARCH_KEY_UP          0x2
+
+static u8 search_key_dn[3] = {0x40, 0x21, 0x02};
+static u8 search_key_up[3] = {0x40, 0x00, 0x00};
+
+static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
+
+       if (hdev_type == GFRM100) {
+               if (usage->hid == (HID_UP_CONSUMER | 0x4)) {
+                       /* Consumer.0004 -> KEY_INFO */
+                       hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_INFO);
+                       return 1;
+               }
+
+               if (usage->hid == (HID_UP_CONSUMER | 0x41)) {
+                       /* Consumer.0041 -> KEY_OK */
+                       hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_OK);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
+               u8 *data, int size)
+{
+       unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
+       int ret = 0;
+
+       if (hdev_type != GFRM100)
+               return 0;
+
+       if (size < 2 || data[0] != GFRM100_SEARCH_KEY_REPORT_ID)
+               return 0;
+
+       /*
+        * Convert GFRM100 Search key reports into Consumer.0221 (Key.Search)
+        * reports. Ignore audio data.
+        */
+       switch (data[1]) {
+       case GFRM100_SEARCH_KEY_DOWN:
+               ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn,
+                                          sizeof(search_key_dn), 1);
+               break;
+
+       case GFRM100_SEARCH_KEY_AUDIO_DATA:
+               break;
+
+       case GFRM100_SEARCH_KEY_UP:
+               ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up,
+                                          sizeof(search_key_up), 1);
+               break;
+
+       default:
+               break;
+       }
+
+       return (ret < 0) ? ret : -1;
+}
+
+static int gfrm_input_configured(struct hid_device *hid, struct hid_input *hidinput)
+{
+       /*
+        * Enable software autorepeat with:
+        * - repeat delay: 400 msec
+        * - repeat period: 100 msec
+        */
+       input_enable_softrepeat(hidinput->input, 400, 100);
+       return 0;
+}
+
+static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       hid_set_drvdata(hdev, (void *) id->driver_data);
+
+       ret = hid_parse(hdev);
+       if (ret)
+               goto done;
+
+       if (id->driver_data == GFRM100) {
+               /*
+                * GFRM100 HID Report Descriptor does not describe the Search
+                * key reports. Thus, we need to add it manually here, so that
+                * those reports reach gfrm_raw_event() from hid_input_report().
+                */
+               if (!hid_register_report(hdev, HID_INPUT_REPORT,
+                                        GFRM100_SEARCH_KEY_REPORT_ID)) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+done:
+       return ret;
+}
+
+static void gfrm_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id gfrm_devices[] = {
+       { HID_BLUETOOTH_DEVICE(0x58, 0x2000),
+               .driver_data = GFRM100 },
+       { HID_BLUETOOTH_DEVICE(0x471, 0x2210),
+               .driver_data = GFRM200 },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, gfrm_devices);
+
+static struct hid_driver gfrm_driver = {
+       .name = "gfrm",
+       .id_table = gfrm_devices,
+       .probe = gfrm_probe,
+       .remove = gfrm_remove,
+       .input_mapping = gfrm_input_mapping,
+       .raw_event = gfrm_raw_event,
+       .input_configured = gfrm_input_configured,
+};
+
+module_hid_driver(gfrm_driver);
+
+MODULE_AUTHOR("Petri Gynther <pgynther@google.com>");
+MODULE_DESCRIPTION("Google Fiber TV Box remote control driver");
+MODULE_LICENSE("GPL");
index f769208276ae4966dff54b1a1c6bf6aa680b84af..ac1feea51be365e3a4c81042b56be75fec26a6a1 100644 (file)
 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
 
+#define USB_VENDOR_ID_CORSAIR          0x1b1c
+#define USB_DEVICE_ID_CORSAIR_K90      0x1b02
+
 #define USB_VENDOR_ID_CREATIVELABS     0x041e
 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
 
 #define USB_DEVICE_ID_DMI_ENC          0x5fab
 
 #define USB_VENDOR_ID_DRAGONRISE       0x0079
+#define USB_DEVICE_ID_DRAGONRISE_WIIU  0x1800
 
 #define USB_VENDOR_ID_DWAV             0x0eef
 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER   0x0001
 
 #define USB_VENDOR_ID_ITE               0x048d
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
+#define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
 
 #define USB_VENDOR_ID_JABRA            0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410  0x0412
 
 #define USB_VENDOR_ID_MADCATZ          0x0738
 #define USB_DEVICE_ID_MADCATZ_BEATPAD  0x4540
+#define USB_DEVICE_ID_MADCATZ_RAT5     0x1705
 #define USB_DEVICE_ID_MADCATZ_RAT9     0x1709
 
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MS_TOUCH_COVER_2   0x07a7
 #define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9
 #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3    0x07dc
+#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2  0x07e2
 #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
 #define USB_DEVICE_ID_MS_TYPE_COVER_3    0x07de
 #define USB_DEVICE_ID_MS_POWER_COVER     0x07da
index 53aeaf6252c75a039cb94a13af27fffbb0f2bddb..2ba6bf69b7d0c45c3ca76b612de5d647d513e3ba 100644 (file)
@@ -1510,8 +1510,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                 * UGCI) cram a lot of unrelated inputs into the
                                 * same interface. */
                                hidinput->report = report;
-                               if (drv->input_configured)
-                                       drv->input_configured(hid, hidinput);
+                               if (drv->input_configured &&
+                                   drv->input_configured(hid, hidinput))
+                                       goto out_cleanup;
                                if (input_register_device(hidinput->input))
                                        goto out_cleanup;
                                hidinput = NULL;
@@ -1532,8 +1533,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
        }
 
        if (hidinput) {
-               if (drv->input_configured)
-                       drv->input_configured(hid, hidinput);
+               if (drv->input_configured &&
+                   drv->input_configured(hid, hidinput))
+                       goto out_cleanup;
                if (input_register_device(hidinput->input))
                        goto out_cleanup;
        }
index e4bc6cb6d7fa5d5481f650c87fde01a7348fdb6a..8979f1fd5208f95e9f707c46b77373f4c975b3b4 100644 (file)
@@ -848,7 +848,7 @@ static void lenovo_remove(struct hid_device *hdev)
        hid_hw_stop(hdev);
 }
 
-static void lenovo_input_configured(struct hid_device *hdev,
+static int lenovo_input_configured(struct hid_device *hdev,
                struct hid_input *hi)
 {
        switch (hdev->product) {
@@ -863,6 +863,8 @@ static void lenovo_input_configured(struct hid_device *hdev,
                        }
                        break;
        }
+
+       return 0;
 }
 
 
index 5332fb7d072a2e2086ba445686a09a9f8dc7d525..c20ac76c0a8cb28ebbc8ea75827f3cfba5e2a787 100644 (file)
@@ -620,6 +620,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                        usage->code == ABS_Y || usage->code == ABS_Z ||
                        usage->code == ABS_RZ)) {
                switch (hdev->product) {
+               case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
                case USB_DEVICE_ID_LOGITECH_WHEEL:
                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
@@ -658,10 +659,18 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
+       struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
+       __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
        struct lg_drv_data *drv_data;
        int ret;
 
+       /* Only work with the 1st interface (G29 presents multiple) */
+       if (iface_num != 0) {
+               dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
+               return -ENODEV;
+       }
+
        drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
        if (!drv_data) {
                hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
index 02cec83caac33f369ef3e46ca3421210144dad84..fbddcb37ae982353e433a67d290f9beb12a506b7 100644 (file)
@@ -45,7 +45,8 @@
 #define LG4FF_MODE_G25_IDX 3
 #define LG4FF_MODE_DFGT_IDX 4
 #define LG4FF_MODE_G27_IDX 5
-#define LG4FF_MODE_MAX_IDX 6
+#define LG4FF_MODE_G29_IDX 6
+#define LG4FF_MODE_MAX_IDX 7
 
 #define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
 #define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
@@ -53,6 +54,7 @@
 #define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
 #define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
 #define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
+#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX)
 
 #define LG4FF_DFEX_TAG "DF-EX"
 #define LG4FF_DFEX_NAME "Driving Force / Formula EX"
@@ -62,6 +64,8 @@
 #define LG4FF_G25_NAME "G25 Racing Wheel"
 #define LG4FF_G27_TAG "G27"
 #define LG4FF_G27_NAME "G27 Racing Wheel"
+#define LG4FF_G29_TAG "G29"
+#define LG4FF_G29_NAME "G29 Racing Wheel"
 #define LG4FF_DFGT_TAG "DFGT"
 #define LG4FF_DFGT_NAME "Driving Force GT"
 
@@ -114,16 +118,12 @@ struct lg4ff_compat_mode_switch {
 };
 
 struct lg4ff_wheel_ident_info {
+       const u32 modes;
        const u16 mask;
        const u16 result;
        const u16 real_product_id;
 };
 
-struct lg4ff_wheel_ident_checklist {
-       const u32 count;
-       const struct lg4ff_wheel_ident_info *models[];
-};
-
 struct lg4ff_multimode_wheel {
        const u16 product_id;
        const u32 alternate_modes;
@@ -144,6 +144,7 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
        {USB_DEVICE_ID_LOGITECH_G25_WHEEL,   lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
        {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,  lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
        {USB_DEVICE_ID_LOGITECH_G27_WHEEL,   lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
+       {USB_DEVICE_ID_LOGITECH_G29_WHEEL,   lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
        {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
        {USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
@@ -161,6 +162,9 @@ static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
        {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
         LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
         LG4FF_G27_TAG, LG4FF_G27_NAME},
+       {USB_DEVICE_ID_LOGITECH_G29_WHEEL,
+        LG4FF_MODE_NATIVE | LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+        LG4FF_G29_TAG, LG4FF_G29_NAME},
 };
 
 static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
@@ -169,41 +173,61 @@ static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
        [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME},
        [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME},
        [LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
-       [LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME}
+       [LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME},
+       [LG4FF_MODE_G29_IDX] = {USB_DEVICE_ID_LOGITECH_G29_WHEEL, LG4FF_G29_TAG, LG4FF_G29_NAME},
 };
 
 /* Multimode wheel identificators */
 static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
+       LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
        0xf000,
        0x1000,
        USB_DEVICE_ID_LOGITECH_DFP_WHEEL
 };
 
 static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
+       LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
        0xff00,
        0x1200,
        USB_DEVICE_ID_LOGITECH_G25_WHEEL
 };
 
 static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
+       LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
        0xfff0,
        0x1230,
        USB_DEVICE_ID_LOGITECH_G27_WHEEL
 };
 
 static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
+       LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
        0xff00,
        0x1300,
        USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
 };
 
+static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info = {
+       LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+       0xfff8,
+       0x1350,
+       USB_DEVICE_ID_LOGITECH_G29_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info2 = {
+       LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+       0xff00,
+       0x8900,
+       USB_DEVICE_ID_LOGITECH_G29_WHEEL
+};
+
 /* Multimode wheel identification checklists */
-static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
-       4,
-       {&lg4ff_dfgt_ident_info,
-        &lg4ff_g27_ident_info,
-        &lg4ff_g25_ident_info,
-        &lg4ff_dfp_ident_info}
+static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
+       &lg4ff_g29_ident_info,
+       &lg4ff_g29_ident_info2,
+       &lg4ff_dfgt_ident_info,
+       &lg4ff_g27_ident_info,
+       &lg4ff_g25_ident_info,
+       &lg4ff_dfp_ident_info
 };
 
 /* Compatibility mode switching commands */
@@ -238,6 +262,12 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
         0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}      /* Switch mode to G27 with detach */
 };
 
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g29 = {
+       2,
+       {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,      /* Revert mode upon USB reset */
+        0xf8, 0x09, 0x05, 0x01, 0x01, 0x00, 0x00}      /* Switch mode to G29 with detach */
+};
+
 /* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
 static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
        1,
@@ -651,6 +681,23 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons
                        return NULL;
                }
                break;
+       case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
+               switch (target_product_id) {
+               case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
+                       return &lg4ff_mode_switch_ext09_dfp;
+               case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
+                       return &lg4ff_mode_switch_ext09_dfgt;
+               case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
+                       return &lg4ff_mode_switch_ext09_g25;
+               case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
+                       return &lg4ff_mode_switch_ext09_g27;
+               case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
+                       return &lg4ff_mode_switch_ext09_g29;
+               /* G29 can only be switched to DF-EX, DFP, DFGT, G25, G27 or its native mode */
+               default:
+                       return NULL;
+               }
+               break;
        case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
                switch (target_product_id) {
                case USB_DEVICE_ID_LOGITECH_WHEEL:
@@ -1037,41 +1084,28 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
 
 static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 reported_product_id, const u16 bcdDevice)
 {
-       const struct lg4ff_wheel_ident_checklist *checklist;
-       int i, from_idx, to_idx;
+       u32 current_mode;
+       int i;
 
-       switch (reported_product_id) {
-       case USB_DEVICE_ID_LOGITECH_WHEEL:
-       case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
-               checklist = &lg4ff_main_checklist;
-               from_idx = 0;
-               to_idx = checklist->count - 1;
-               break;
-       case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
-               checklist = &lg4ff_main_checklist;
-               from_idx = 0;
-               to_idx = checklist->count - 2; /* End identity check at G25 */
-               break;
-       case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
-               checklist = &lg4ff_main_checklist;
-               from_idx = 1; /* Start identity check at G27 */
-               to_idx = checklist->count - 3; /* End identity check at G27 */
-               break;
-       case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
-               checklist = &lg4ff_main_checklist;
-               from_idx = 0;
-               to_idx = checklist->count - 4; /* End identity check at DFGT */
-               break;
-       default:
-               return 0;
+       /* identify current mode from USB PID */
+       for (i = 1; i < ARRAY_SIZE(lg4ff_alternate_modes); i++) {
+               dbg_hid("Testing whether PID is %X\n", lg4ff_alternate_modes[i].product_id);
+               if (reported_product_id == lg4ff_alternate_modes[i].product_id)
+                       break;
        }
 
-       for (i = from_idx; i <= to_idx; i++) {
-               const u16 mask = checklist->models[i]->mask;
-               const u16 result = checklist->models[i]->result;
-               const u16 real_product_id = checklist->models[i]->real_product_id;
+       if (i == ARRAY_SIZE(lg4ff_alternate_modes))
+               return 0;
+
+       current_mode = BIT(i);
+
+       for (i = 0; i < ARRAY_SIZE(lg4ff_main_checklist); i++) {
+               const u16 mask = lg4ff_main_checklist[i]->mask;
+               const u16 result = lg4ff_main_checklist[i]->result;
+               const u16 real_product_id = lg4ff_main_checklist[i]->real_product_id;
 
-               if ((bcdDevice & mask) == result) {
+               if ((current_mode & lg4ff_main_checklist[i]->modes) && \
+                               (bcdDevice & mask) == result) {
                        dbg_hid("Found wheel with real PID %X whose reported PID is %X\n", real_product_id, reported_product_id);
                        return real_product_id;
                }
@@ -1246,12 +1280,13 @@ int lg4ff_init(struct hid_device *hid)
                entry->wdata.set_range(hid, entry->wdata.range);
 
 #ifdef CONFIG_LEDS_CLASS
-       /* register led subsystem - G27 only */
+       /* register led subsystem - G27/G29 only */
        entry->wdata.led_state = 0;
        for (j = 0; j < 5; j++)
                entry->wdata.led[j] = NULL;
 
-       if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
+       if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL ||
+                       lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) {
                struct led_classdev *led;
                size_t name_sz;
                char *name;
index 484196459305577c19433fe4fe35b21c2ac39905..5fd97860aec4d8ec1e92b02031e715e8644367e8 100644 (file)
@@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644);
 MODULE_PARM_DESC(disable_raw_mode,
        "Disable Raw mode reporting for touchpads and keep firmware gestures.");
 
+static bool disable_tap_to_click;
+module_param(disable_tap_to_click, bool, 0644);
+MODULE_PARM_DESC(disable_tap_to_click,
+       "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently).");
+
 #define REPORT_ID_HIDPP_SHORT                  0x10
 #define REPORT_ID_HIDPP_LONG                   0x11
 
@@ -41,10 +46,15 @@ MODULE_PARM_DESC(disable_raw_mode,
 
 #define HIDPP_QUIRK_CLASS_WTP                  BIT(0)
 #define HIDPP_QUIRK_CLASS_M560                 BIT(1)
+#define HIDPP_QUIRK_CLASS_K400                 BIT(2)
 
 /* bits 2..20 are reserved for classes */
-#define HIDPP_QUIRK_DELAYED_INIT               BIT(21)
+#define HIDPP_QUIRK_CONNECT_EVENTS             BIT(21)
 #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS       BIT(22)
+#define HIDPP_QUIRK_NO_HIDINPUT                        BIT(23)
+
+#define HIDPP_QUIRK_DELAYED_INIT               (HIDPP_QUIRK_NO_HIDINPUT | \
+                                                HIDPP_QUIRK_CONNECT_EVENTS)
 
 /*
  * There are two hidpp protocols in use, the first version hidpp10 is known
@@ -552,6 +562,52 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
        return name;
 }
 
+/* -------------------------------------------------------------------------- */
+/* 0x6010: Touchpad FW items                                                  */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_TOUCHPAD_FW_ITEMS                   0x6010
+
+#define CMD_TOUCHPAD_FW_ITEMS_SET                      0x10
+
+struct hidpp_touchpad_fw_items {
+       uint8_t presence;
+       uint8_t desired_state;
+       uint8_t state;
+       uint8_t persistent;
+};
+
+/**
+ * send a set state command to the device by reading the current items->state
+ * field. items is then filled with the current state.
+ */
+static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp,
+                                      u8 feature_index,
+                                      struct hidpp_touchpad_fw_items *items)
+{
+       struct hidpp_report response;
+       int ret;
+       u8 *params = (u8 *)response.fap.params;
+
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+               CMD_TOUCHPAD_FW_ITEMS_SET, &items->state, 1, &response);
+
+       if (ret > 0) {
+               hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+                       __func__, ret);
+               return -EPROTO;
+       }
+       if (ret)
+               return ret;
+
+       items->presence = params[0];
+       items->desired_state = params[1];
+       items->state = params[2];
+       items->persistent = params[3];
+
+       return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* 0x6100: TouchPadRawXY                                                      */
 /* -------------------------------------------------------------------------- */
@@ -1132,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return -1;
 }
 
+/* ------------------------------------------------------------------------- */
+/* Logitech K400 devices                                                     */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * The Logitech K400 keyboard has an embedded touchpad which is seen
+ * as a mouse from the OS point of view. There is a hardware shortcut to disable
+ * tap-to-click but the setting is not remembered accross reset, annoying some
+ * users.
+ *
+ * We can toggle this feature from the host by using the feature 0x6010:
+ * Touchpad FW items
+ */
+
+struct k400_private_data {
+       u8 feature_index;
+};
+
+static int k400_disable_tap_to_click(struct hidpp_device *hidpp)
+{
+       struct k400_private_data *k400 = hidpp->private_data;
+       struct hidpp_touchpad_fw_items items = {};
+       int ret;
+       u8 feature_type;
+
+       if (!k400->feature_index) {
+               ret = hidpp_root_get_feature(hidpp,
+                       HIDPP_PAGE_TOUCHPAD_FW_ITEMS,
+                       &k400->feature_index, &feature_type);
+               if (ret)
+                       /* means that the device is not powered up */
+                       return ret;
+       }
+
+       ret = hidpp_touchpad_fw_items_set(hidpp, k400->feature_index, &items);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int k400_allocate(struct hid_device *hdev)
+{
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+       struct k400_private_data *k400;
+
+       k400 = devm_kzalloc(&hdev->dev, sizeof(struct k400_private_data),
+                           GFP_KERNEL);
+       if (!k400)
+               return -ENOMEM;
+
+       hidpp->private_data = k400;
+
+       return 0;
+};
+
+static int k400_connect(struct hid_device *hdev, bool connected)
+{
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+
+       if (!connected)
+               return 0;
+
+       if (!disable_tap_to_click)
+               return 0;
+
+       return k400_disable_tap_to_click(hidpp);
+}
+
 /* -------------------------------------------------------------------------- */
 /* Generic HID++ devices                                                      */
 /* -------------------------------------------------------------------------- */
@@ -1160,13 +1285,15 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
                m560_populate_input(hidpp, input, origin_is_hid_core);
 }
 
-static void hidpp_input_configured(struct hid_device *hdev,
+static int hidpp_input_configured(struct hid_device *hdev,
                                struct hid_input *hidinput)
 {
        struct hidpp_device *hidpp = hid_get_drvdata(hdev);
        struct input_dev *input = hidinput->input;
 
        hidpp_populate_input(hidpp, input, true);
+
+       return 0;
 }
 
 static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
@@ -1203,7 +1330,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
        if (unlikely(hidpp_report_is_connect_event(report))) {
                atomic_set(&hidpp->connected,
                                !(report->rap.params[0] & (1 << 6)));
-               if ((hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) &&
+               if ((hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) &&
                    (schedule_work(&hidpp->work) == 0))
                        dbg_hid("%s: connect event already queued\n", __func__);
                return 1;
@@ -1328,23 +1455,30 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
                ret = m560_send_config_command(hdev, connected);
                if (ret)
                        return;
+       } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
+               ret = k400_connect(hdev, connected);
+               if (ret)
+                       return;
        }
 
        if (!connected || hidpp->delayed_input)
                return;
 
+       /* the device is already connected, we can ask for its name and
+        * protocol */
        if (!hidpp->protocol_major) {
                ret = !hidpp_is_connected(hidpp);
                if (ret) {
                        hid_err(hdev, "Can not get the protocol version.\n");
                        return;
                }
+               hid_info(hdev, "HID++ %u.%u device connected.\n",
+                        hidpp->protocol_major, hidpp->protocol_minor);
        }
 
-       /* the device is already connected, we can ask for its name and
-        * protocol */
-       hid_info(hdev, "HID++ %u.%u device connected.\n",
-                hidpp->protocol_major, hidpp->protocol_minor);
+       if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT))
+               /* if HID created the input nodes for us, we can stop now */
+               return;
 
        if (!hidpp->name || hidpp->name == hdev->name) {
                name = hidpp_get_device_name(hidpp);
@@ -1397,7 +1531,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        if (disable_raw_mode) {
                hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
-               hidpp->quirks &= ~HIDPP_QUIRK_DELAYED_INIT;
+               hidpp->quirks &= ~HIDPP_QUIRK_CONNECT_EVENTS;
+               hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
        }
 
        if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
@@ -1408,6 +1543,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                ret = m560_allocate(hdev);
                if (ret)
                        goto allocate_fail;
+       } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
+               ret = k400_allocate(hdev);
+               if (ret)
+                       goto allocate_fail;
        }
 
        INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1448,7 +1587,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
        /* Block incoming packets */
        hid_device_io_stop(hdev);
 
-       if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
+       if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
                connect_mask &= ~HID_CONNECT_HIDINPUT;
 
        ret = hid_hw_start(hdev, connect_mask);
@@ -1457,7 +1596,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto hid_hw_start_fail;
        }
 
-       if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) {
+       if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
                /* Allow incoming packets */
                hid_device_io_start(hdev);
 
@@ -1502,6 +1641,10 @@ static const struct hid_device_id hidpp_devices[] = {
          HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, 0x402d),
          .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
+       { /* Keyboard logitech K400 */
+         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
+               USB_VENDOR_ID_LOGITECH, 0x4024),
+         .driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 },
 
        { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
index 29a74c1efcb85fa727536c4b72be844f9963cd70..d6fa496d0ca25c17035233315ba9f5d5ebddc4fd 100644 (file)
@@ -471,18 +471,22 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
        return 0;
 }
 
-static void magicmouse_input_configured(struct hid_device *hdev,
+static int magicmouse_input_configured(struct hid_device *hdev,
                struct hid_input *hi)
 
 {
        struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+       int ret;
 
-       int ret = magicmouse_setup_input(msc->input, hdev);
+       ret = magicmouse_setup_input(msc->input, hdev);
        if (ret) {
                hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
                /* clean msc->input to notify probe() of the failure */
                msc->input = NULL;
+               return ret;
        }
+
+       return 0;
 }
 
 
index 9aa3515090a7252abc0459c8849bc9bea32d733e..77a2cf3e4afec25eee5d5d313f63caaf9939653f 100644 (file)
@@ -278,6 +278,8 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_DUPLICATE_USAGES },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3),
                .driver_data = MS_HIDINPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2),
+               .driver_data = MS_HIDINPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
                .driver_data = MS_HIDINPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
index 426b2f1a34501c7516ab39dc631d3c2073591aac..3d664d01305e5ef32301fdcf53a4f3bbee61f027 100644 (file)
@@ -309,6 +309,41 @@ static struct attribute_group mt_attribute_group = {
        .attrs = sysfs_attrs
 };
 
+static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+{
+       struct mt_device *td = hid_get_drvdata(hdev);
+       int ret, size = hid_report_len(report);
+       u8 *buf;
+
+       /*
+        * Only fetch the feature report if initial reports are not already
+        * been retrieved. Currently this is only done for Windows 8 touch
+        * devices.
+        */
+       if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS))
+               return;
+       if (td->mtclass.name != MT_CLS_WIN_8)
+               return;
+
+       buf = hid_alloc_report_buf(report, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       ret = hid_hw_raw_request(hdev, report->id, buf, size,
+                                HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+       if (ret < 0) {
+               dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+                        report->id);
+       } else {
+               ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+                                          size, 0);
+               if (ret)
+                       dev_warn(&hdev->dev, "failed to report feature\n");
+       }
+
+       kfree(buf);
+}
+
 static void mt_feature_mapping(struct hid_device *hdev,
                struct hid_field *field, struct hid_usage *usage)
 {
@@ -327,6 +362,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
 
                break;
        case HID_DG_CONTACTMAX:
+               mt_get_feature(hdev, field->report);
+
                td->maxcontact_report_id = field->report->id;
                td->maxcontacts = field->value[0];
                if (!td->maxcontacts &&
@@ -343,6 +380,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
                        break;
                }
 
+               mt_get_feature(hdev, field->report);
                if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
                        td->is_buttonpad = true;
 
@@ -725,12 +763,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
                mt_sync_frame(td, report->field[0]->hidinput->input);
 }
 
-static void mt_touch_input_configured(struct hid_device *hdev,
+static int mt_touch_input_configured(struct hid_device *hdev,
                                        struct hid_input *hi)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
        struct mt_class *cls = &td->mtclass;
        struct input_dev *input = hi->input;
+       int ret;
 
        if (!td->maxcontacts)
                td->maxcontacts = MT_DEFAULT_MAXCONTACT;
@@ -752,9 +791,12 @@ static void mt_touch_input_configured(struct hid_device *hdev,
        if (td->is_buttonpad)
                __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 
-       input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+       ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+       if (ret)
+               return ret;
 
        td->mt_flags = 0;
+       return 0;
 }
 
 static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -930,15 +972,19 @@ static void mt_post_parse(struct mt_device *td)
                cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
-static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
        char *name;
        const char *suffix = NULL;
        struct hid_field *field = hi->report->field[0];
+       int ret;
 
-       if (hi->report->id == td->mt_report_id)
-               mt_touch_input_configured(hdev, hi);
+       if (hi->report->id == td->mt_report_id) {
+               ret = mt_touch_input_configured(hdev, hi);
+               if (ret)
+                       return ret;
+       }
 
        /*
         * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
@@ -968,6 +1014,9 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
                case HID_DG_TOUCHSCREEN:
                        /* we do not set suffix = "Touchscreen" */
                        break;
+               case HID_DG_TOUCHPAD:
+                       suffix = "Touchpad";
+                       break;
                case HID_GD_SYSTEM_CONTROL:
                        suffix = "System Control";
                        break;
@@ -989,6 +1038,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
                        hi->input->name = name;
                }
        }
+
+       return 0;
 }
 
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -1026,8 +1077,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
                 * reports. Fortunately, the Win8 spec says that all touches
                 * should be sent during each report, making the initialization
                 * of input reports unnecessary.
+                *
+                * In addition some touchpads do not behave well if we read
+                * all feature reports from them. Instead we prevent
+                * initial report fetching and then selectively fetch each
+                * report we are interested in.
                 */
-               hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS;
+               hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
 
        td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
        if (!td) {
index 600f2075512ff1895852212c67a0fbcb9764566c..756d1ef9bd991d9f77df5835f0cb1f44391493ed 100644 (file)
@@ -859,14 +859,14 @@ not_claimed_input:
        return 1;
 }
 
-static void ntrig_input_configured(struct hid_device *hid,
+static int ntrig_input_configured(struct hid_device *hid,
                struct hid_input *hidinput)
 
 {
        struct input_dev *input = hidinput->input;
 
        if (hidinput->report->maxfield < 1)
-               return;
+               return 0;
 
        switch (hidinput->report->field[0]->application) {
        case HID_DG_PEN:
@@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid,
                                                        "N-Trig MultiTouch";
                break;
        }
+
+       return 0;
 }
 
 static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
index e3e98ccf137b54bae52fcd5cd0ded68b839742bf..3a207c0ac0e39678da16a01e0412a391d2a22cfc 100644 (file)
@@ -427,7 +427,7 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data)
                                        pm->midi_octave = 2;
                                dbg_hid("pcmidi mode: %d octave: %d\n",
                                        pm->midi_mode, pm->midi_octave);
-                           continue;
+                               continue;
                        } else
                                key = KEY_MESSENGER;
                        break;
@@ -695,7 +695,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
        if (err < 0) {
                pk_error("failed to register pc-midi sound card: error %d\n",
                         err);
-                        goto fail_register;
+               goto fail_register;
        }
 
        dbg_hid("pcmidi_snd_initialise finished ok\n");
index 2c148129beb2f0a746f4661660be47e79421274e..67cd059a8f46cdf7dab8d73cb0edb7bd5aff1333 100644 (file)
@@ -1173,7 +1173,7 @@ static int rmi_populate(struct hid_device *hdev)
        return 0;
 }
 
-static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
+static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct rmi_data *data = hid_get_drvdata(hdev);
        struct input_dev *input = hi->input;
@@ -1185,10 +1185,10 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
        hid_dbg(hdev, "Opening low level driver\n");
        ret = hid_hw_open(hdev);
        if (ret)
-               return;
+               return ret;
 
        if (!(data->device_flags & RMI_DEVICE))
-               return;
+               return 0;
 
        /* Allow incoming hid reports */
        hid_device_io_start(hdev);
@@ -1228,7 +1228,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
        input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
        input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
 
-       input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
+       ret = input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
+       if (ret < 0)
+               goto exit;
 
        if (data->button_count) {
                __set_bit(EV_KEY, input->evbit);
@@ -1244,6 +1246,7 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
 exit:
        hid_device_io_stop(hdev);
        hid_hw_close(hdev);
+       return ret;
 }
 
 static int rmi_input_mapping(struct hid_device *hdev,
index a014f21275d8bfada33701b4bef5013f3b81eb2a..2f84b26f116706c131abda474ab855d1aff11cfa 100644 (file)
@@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id saitek_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
                .driver_data = SAITEK_FIX_PS1000 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5),
+               .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
                .driver_data = SAITEK_RELEASE_MODE_RAT7 },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
index a76eb2a0a987b33da708dbbaf581ef914901ffbd..92870cdb52d946a7408463a5b249129befd5e91d 100644 (file)
@@ -593,6 +593,20 @@ static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                }
        }
 
+       /* Checks if the report descriptor of Thinkpad Helix 2 has a logical
+        * minimum for magnetic flux axis greater than the maximum */
+       if (hdev->product == USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA &&
+               *rsize == 2558 && rdesc[913] == 0x17 && rdesc[914] == 0x40 &&
+               rdesc[915] == 0x81 && rdesc[916] == 0x08 &&
+               rdesc[917] == 0x00 && rdesc[918] == 0x27 &&
+               rdesc[921] == 0x07 && rdesc[922] == 0x00) {
+               /* Sets negative logical minimum for mag x, y and z */
+               rdesc[914] = rdesc[935] = rdesc[956] = 0xc0;
+               rdesc[915] = rdesc[936] = rdesc[957] = 0x7e;
+               rdesc[916] = rdesc[937] = rdesc[958] = 0xf7;
+               rdesc[917] = rdesc[938] = rdesc[959] = 0xff;
+       }
+
        return rdesc;
 }
 
@@ -646,8 +660,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
                                                      GFP_KERNEL);
        if (sd->hid_sensor_hub_client_devs == NULL) {
                hid_err(hdev, "Failed to allocate memory for mfd cells\n");
-                       ret = -ENOMEM;
-                       goto err_stop_hw;
+               ret = -ENOMEM;
+               goto err_stop_hw;
        }
 
        for (i = 0; i < hdev->maxcollection; ++i) {
@@ -684,8 +698,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
                                              collection->usage);
                        if (name == NULL) {
                                hid_err(hdev, "Failed MFD device name\n");
-                                       ret = -ENOMEM;
-                                       goto err_stop_hw;
+                               ret = -ENOMEM;
+                               goto err_stop_hw;
                        }
                        sd->hid_sensor_hub_client_devs[
                                sd->hid_sensor_client_cnt].name = name;
@@ -777,6 +791,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
                        USB_DEVICE_ID_ITE_LENOVO_YOGA),
                        .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
+                       USB_DEVICE_ID_ITE_LENOVO_YOGA2),
+                       .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
                     HID_ANY_ID) },
        { }
index 661f94f8ab8b0b0aafc9dace1073b08849e23784..774cd221056659f5bacd480b8b07744c1a5a138f 100644 (file)
@@ -1360,20 +1360,27 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count,
        return 0;
 }
 
-static void sony_input_configured(struct hid_device *hdev,
+static int sony_input_configured(struct hid_device *hdev,
                                        struct hid_input *hidinput)
 {
        struct sony_sc *sc = hid_get_drvdata(hdev);
+       int ret;
 
        /*
         * The Dualshock 4 touchpad supports 2 touches and has a
         * resolution of 1920x942 (44.86 dots/mm).
         */
        if (sc->quirks & DUALSHOCK4_CONTROLLER) {
-               if (sony_register_touchpad(hidinput, 2, 1920, 942) != 0)
+               ret = sony_register_touchpad(hidinput, 2, 1920, 942);
+               if (ret) {
                        hid_err(sc->hdev,
-                               "Unable to initialize multi-touch slots\n");
+                               "Unable to initialize multi-touch slots: %d\n",
+                               ret);
+                       return ret;
+               }
        }
+
+       return 0;
 }
 
 /*
index b905d501e752d607b6fc1731ad89ff3d23ce7cd0..85ac43517e3ffc3232461f54d43054cd36a39a29 100644 (file)
@@ -731,7 +731,7 @@ static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 0;
 }
 
-static void uclogic_input_configured(struct hid_device *hdev,
+static int uclogic_input_configured(struct hid_device *hdev,
                struct hid_input *hi)
 {
        char *name;
@@ -741,7 +741,7 @@ static void uclogic_input_configured(struct hid_device *hdev,
 
        /* no report associated (HID_QUIRK_MULTI_INPUT not set) */
        if (!hi->report)
-               return;
+               return 0;
 
        field = hi->report->field[0];
 
@@ -774,6 +774,8 @@ static void uclogic_input_configured(struct hid_device *hdev,
                        hi->input->name = name;
                }
        }
+
+       return 0;
 }
 
 /**
index 2871f3c81a4cceb521f4c26aac4da75466f5db6f..10bd8e6e4c9c814cbceb863bbff4a87f3d3a283a 100644 (file)
@@ -1028,6 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
 
        snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
                 client->name, hid->vendor, hid->product);
+       strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
 
        ret = hid_add_device(hid);
        if (ret) {
index 1dff8f0015bac2bfd76c6946bdca8d0fdd00d73d..94bb137abe3281bfb023c7bc438ad8bcf0d716a4 100644 (file)
@@ -71,6 +71,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL },
@@ -91,6 +92,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
index 9a4912c1828dad3109b9473305670c79fc20d022..e06af5b9f59e822e7d2a38e3cfcc478961e7a207 100644 (file)
@@ -211,7 +211,7 @@ static void wacom_usage_mapping(struct hid_device *hdev,
         * Bamboo models do not support HID_DG_CONTACTMAX.
         * And, Bamboo Pen only descriptor contains touch.
         */
-       if (features->type != BAMBOO_PT) {
+       if (features->type > BAMBOO_PT) {
                /* ISDv4 touch devices at least supports one touch point */
                if (finger && !features->touch_max)
                        features->touch_max = 1;
@@ -222,7 +222,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
                features->x_max = field->logical_maximum;
                if (finger) {
                        features->x_phy = field->physical_maximum;
-                       if (features->type != BAMBOO_PT) {
+                       if ((features->type != BAMBOO_PT) &&
+                           (features->type != BAMBOO_TOUCH)) {
                                features->unit = field->unit;
                                features->unitExpo = field->unit_exponent;
                        }
@@ -232,7 +233,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
                features->y_max = field->logical_maximum;
                if (finger) {
                        features->y_phy = field->physical_maximum;
-                       if (features->type != BAMBOO_PT) {
+                       if ((features->type != BAMBOO_PT) &&
+                           (features->type != BAMBOO_TOUCH)) {
                                features->unit = field->unit;
                                features->unitExpo = field->unit_exponent;
                        }
@@ -420,7 +422,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
                        /* MT Tablet PC touch */
                        return wacom_set_device_mode(hdev, 3, 4, 4);
                }
-               else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
+               else if (features->type == WACOM_24HDT) {
                        return wacom_set_device_mode(hdev, 18, 3, 2);
                }
                else if (features->type == WACOM_27QHDT) {
@@ -430,7 +432,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
                        return wacom_set_device_mode(hdev, 2, 2, 2);
                }
        } else if (features->device_type & WACOM_DEVICETYPE_PEN) {
-               if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
+               if (features->type <= BAMBOO_PT) {
                        return wacom_set_device_mode(hdev, 2, 2, 2);
                }
        }
@@ -1547,15 +1549,16 @@ static void wacom_wireless_work(struct work_struct *work)
                wacom_wac1->features =
                        *((struct wacom_features *)id->driver_data);
                wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN;
-               if (wacom_wac1->features.type != INTUOSHT &&
-                   wacom_wac1->features.type != BAMBOO_PT)
-                       wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
                wacom_set_default_phy(&wacom_wac1->features);
                wacom_calculate_res(&wacom_wac1->features);
                snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
                         wacom_wac1->features.name);
-               snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
-                        wacom_wac1->features.name);
+               if (wacom_wac1->features.type < BAMBOO_PEN ||
+                   wacom_wac1->features.type > BAMBOO_PT) {
+                       snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
+                                wacom_wac1->features.name);
+                       wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
+               }
                wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
                wacom_wac1->shared->type = wacom_wac1->features.type;
                wacom_wac1->pid = wacom_wac->pid;
@@ -1566,7 +1569,8 @@ static void wacom_wireless_work(struct work_struct *work)
 
                /* Touch interface */
                if (wacom_wac1->features.touch_max ||
-                   wacom_wac1->features.type == INTUOSHT) {
+                   (wacom_wac1->features.type >= INTUOSHT &&
+                   wacom_wac1->features.type <= BAMBOO_PT)) {
                        wacom_wac2->features =
                                *((struct wacom_features *)id->driver_data);
                        wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
@@ -1575,20 +1579,22 @@ static void wacom_wireless_work(struct work_struct *work)
                        wacom_calculate_res(&wacom_wac2->features);
                        snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
                                 "%s (WL) Finger",wacom_wac2->features.name);
-                       snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
-                                "%s (WL) Pad",wacom_wac2->features.name);
                        if (wacom_wac1->features.touch_max)
                                wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH;
-                       if (wacom_wac1->features.type == INTUOSHT ||
-                           wacom_wac1->features.type == BAMBOO_PT)
+                       if (wacom_wac1->features.type >= INTUOSHT &&
+                           wacom_wac1->features.type <= BAMBOO_PT) {
+                               snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
+                                        "%s (WL) Pad",wacom_wac2->features.name);
                                wacom_wac2->features.device_type |= WACOM_DEVICETYPE_PAD;
+                       }
                        wacom_wac2->pid = wacom_wac->pid;
                        error = wacom_allocate_inputs(wacom2) ||
                                wacom_register_inputs(wacom2);
                        if (error)
                                goto fail;
 
-                       if (wacom_wac1->features.type == INTUOSHT &&
+                       if ((wacom_wac1->features.type == INTUOSHT ||
+                           wacom_wac1->features.type == INTUOSHT2) &&
                            wacom_wac1->features.touch_max)
                                wacom_wac->shared->touch_input = wacom_wac2->touch_input;
                }
@@ -1812,11 +1818,27 @@ static int wacom_probe(struct hid_device *hdev,
        /* Note that if query fails it is not a hard failure */
        wacom_query_tablet_data(hdev, features);
 
+       /* touch only Bamboo doesn't support pen */
+       if ((features->type == BAMBOO_TOUCH) &&
+           (features->device_type & WACOM_DEVICETYPE_PEN)) {
+               error = -ENODEV;
+               goto fail_hw_start;
+       }
+
+       /* pen only Bamboo neither support touch nor pad */
+       if ((features->type == BAMBOO_PEN) &&
+           ((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
+           (features->device_type & WACOM_DEVICETYPE_PAD))) {
+               error = -ENODEV;
+               goto fail_hw_start;
+       }
+
        if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
                error = hid_hw_open(hdev);
 
-       if (wacom_wac->features.type == INTUOSHT && 
-           wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
+       if ((wacom_wac->features.type == INTUOSHT ||
+           wacom_wac->features.type == INTUOSHT2) &&
+           (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
                        wacom_wac->shared->touch_input = wacom_wac->touch_input;
        }
 
index 0215ab62bb93f1b3669ed02ba1087ab43ffa6456..8b29949507d1692f436b1db5045ca7ed4b8d54f3 100644 (file)
@@ -765,13 +765,15 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
        /* general pen packet */
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               if (features->type >= INTUOS4S && features->type <= CINTIQ_HYBRID) {
+               if (features->pressure_max == 2047) {
                        t = (t << 1) | (data[1] & 1);
                }
                input_report_abs(input, ABS_PRESSURE, t);
-               input_report_abs(input, ABS_TILT_X,
+               if (features->type != INTUOSHT2) {
+                   input_report_abs(input, ABS_TILT_X,
                                 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
-               input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+                   input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+               }
                input_report_key(input, BTN_STYLUS, data[1] & 2);
                input_report_key(input, BTN_STYLUS2, data[1] & 4);
                input_report_key(input, BTN_TOUCH, t > 10);
@@ -799,6 +801,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
            data[0] != WACOM_REPORT_INTUOSREAD &&
            data[0] != WACOM_REPORT_INTUOSWRITE &&
            data[0] != WACOM_REPORT_INTUOSPAD &&
+           data[0] != WACOM_REPORT_INTUOS_PEN &&
            data[0] != WACOM_REPORT_CINTIQ &&
            data[0] != WACOM_REPORT_CINTIQPAD &&
            data[0] != WACOM_REPORT_INTUOS5PAD) {
@@ -948,6 +951,27 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                        } else {
                                input_report_abs(input, ABS_MISC, 0);
                        }
+
+               } else if (features->type == CINTIQ_COMPANION_2) {
+                       input_report_key(input, BTN_1, (data[1] & 0x02));
+                       input_report_key(input, BTN_2, (data[2] & 0x01));
+                       input_report_key(input, BTN_3, (data[2] & 0x02));
+                       input_report_key(input, BTN_4, (data[2] & 0x04));
+                       input_report_key(input, BTN_5, (data[2] & 0x08));
+                       input_report_key(input, BTN_6, (data[1] & 0x04));
+
+                       input_report_key(input, BTN_7, (data[2] & 0x10));  /* Right  */
+                       input_report_key(input, BTN_8, (data[2] & 0x20));  /* Up         */
+                       input_report_key(input, BTN_9, (data[2] & 0x40));  /* Left   */
+                       input_report_key(input, BTN_A, (data[2] & 0x80));  /* Down   */
+                       input_report_key(input, BTN_0, (data[1] & 0x01));  /* Center */
+
+                       if (data[2] | (data[1] & 0x07)) {
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
+
                } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
                        int i;
 
@@ -1628,6 +1652,7 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
                break;
        case HID_DG_CONTACTCOUNT:
+               wacom_wac->hid_data.cc_report = field->report->id;
                wacom_wac->hid_data.cc_index = field->index;
                wacom_wac->hid_data.cc_value_index = usage->usage_index;
                break;
@@ -1715,7 +1740,32 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct hid_data* hid_data = &wacom_wac->hid_data;
 
-       if (hid_data->cc_index >= 0) {
+       if (hid_data->cc_report != 0 &&
+           hid_data->cc_report != report->id) {
+               int i;
+
+               hid_data->cc_report = report->id;
+               hid_data->cc_index = -1;
+               hid_data->cc_value_index = -1;
+
+               for (i = 0; i < report->maxfield; i++) {
+                       struct hid_field *field = report->field[i];
+                       int j;
+
+                       for (j = 0; j < field->maxusage; j++) {
+                               if (field->usage[j].hid == HID_DG_CONTACTCOUNT) {
+                                       hid_data->cc_index = i;
+                                       hid_data->cc_value_index = j;
+
+                                       /* break */
+                                       i = report->maxfield;
+                                       j = field->maxusage;
+                               }
+                       }
+               }
+       }
+       if (hid_data->cc_report != 0 &&
+           hid_data->cc_index >= 0) {
                struct hid_field *field = report->field[hid_data->cc_index];
                int value = field->value[hid_data->cc_value_index];
                if (value)
@@ -1896,7 +1946,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                int y = (data[3] << 4) | (data[4] & 0x0f);
                int width, height;
 
-               if (features->type >= INTUOSPS && features->type <= INTUOSHT) {
+               if (features->type >= INTUOSPS && features->type <= INTUOSHT2) {
                        width  = data[5] * 100;
                        height = data[6] * 100;
                } else {
@@ -1924,7 +1974,7 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
        struct input_dev *input = wacom->pad_input;
        struct wacom_features *features = &wacom->features;
 
-       if (features->type == INTUOSHT) {
+       if (features->type == INTUOSHT || features->type == INTUOSHT2) {
                input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
                input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
        } else {
@@ -1939,7 +1989,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
 {
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
-       int i;
+       int  touch_changed = 0, i;
 
        if (data[0] != 0x02)
            return 0;
@@ -1949,15 +1999,16 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int offset = (8 * i) + 2;
                int msg_id = data[offset];
 
-               if (msg_id >= 2 && msg_id <= 17)
+               if (msg_id >= 2 && msg_id <= 17) {
                        wacom_bpt3_touch_msg(wacom, data + offset);
-               else if (msg_id == 128)
+                       touch_changed++;
+               } else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
 
-       /* only update the touch if we actually have a touchpad */
-       if (wacom->touch_registered) {
+       /* only update touch if we actually have a touchpad and touch data changed */
+       if (wacom->touch_registered && touch_changed) {
                input_mt_sync_frame(wacom->touch_input);
                wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
@@ -2038,7 +2089,12 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
 
 static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
 {
-       if (len == WACOM_PKGLEN_BBTOUCH)
+       struct wacom_features *features = &wacom->features;
+
+       if ((features->type == INTUOSHT2) &&
+           (features->device_type & WACOM_DEVICETYPE_PEN))
+               return wacom_intuos_irq(wacom);
+       else if (len == WACOM_PKGLEN_BBTOUCH)
                return wacom_bpt_touch(wacom);
        else if (len == WACOM_PKGLEN_BBTOUCH3)
                return wacom_bpt3_touch(wacom);
@@ -2145,7 +2201,8 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
        if (connected) {
                int pid, battery, charging;
 
-               if ((wacom->shared->type == INTUOSHT) &&
+               if ((wacom->shared->type == INTUOSHT ||
+                   wacom->shared->type == INTUOSHT2) &&
                    wacom->shared->touch_input &&
                    wacom->shared->touch_max) {
                        input_report_switch(wacom->shared->touch_input,
@@ -2183,7 +2240,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
        if (data[0] != WACOM_REPORT_USB)
                return 0;
 
-       if (features->type == INTUOSHT &&
+       if ((features->type == INTUOSHT ||
+           features->type == INTUOSHT2) &&
            wacom_wac->shared->touch_input &&
            features->touch_max) {
                input_report_switch(wacom_wac->shared->touch_input,
@@ -2264,6 +2322,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        case WACOM_27QHD:
        case DTK:
        case CINTIQ_HYBRID:
+       case CINTIQ_COMPANION_2:
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
@@ -2300,7 +2359,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                break;
 
        case BAMBOO_PT:
+       case BAMBOO_PEN:
+       case BAMBOO_TOUCH:
        case INTUOSHT:
+       case INTUOSHT2:
                if (wacom_wac->data[0] == WACOM_REPORT_USB)
                        sync = wacom_status_irq(wacom_wac, len);
                else
@@ -2337,22 +2399,31 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        }
 }
 
-static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
+static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac)
 {
        struct input_dev *input_dev = wacom_wac->pen_input;
 
        input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
 
-       __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
        __set_bit(BTN_TOOL_PEN, input_dev->keybit);
-       __set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
-       __set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
-       __set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
        __set_bit(BTN_STYLUS, input_dev->keybit);
        __set_bit(BTN_STYLUS2, input_dev->keybit);
 
        input_set_abs_params(input_dev, ABS_DISTANCE,
                             0, wacom_wac->features.distance_max, 0, 0);
+}
+
+static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
+{
+       struct input_dev *input_dev = wacom_wac->pen_input;
+
+       wacom_setup_basic_pro_pen(wacom_wac);
+
+       __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+       __set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
+       __set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
+       __set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
+
        input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
        input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, 0, 0);
        input_abs_set_res(input_dev, ABS_TILT_X, 57);
@@ -2387,9 +2458,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
 
        /* The pen and pad share the same interface on most devices */
        if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
-           features->type == DTUS || features->type == WACOM_MO ||
-           (features->type >= INTUOS3S && features->type <= WACOM_13HD && 
-            features->type != INTUOSHT)) {
+           features->type == DTUS ||
+           (features->type >= INTUOS3S && features->type <= WACOM_MO)) {
                if (features->device_type & WACOM_DEVICETYPE_PEN)
                        features->device_type |= WACOM_DEVICETYPE_PAD;
        }
@@ -2406,12 +2476,12 @@ void wacom_setup_device_quirks(struct wacom *wacom)
         * interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
         * tablet values.
         */
-       if ((features->type >= INTUOS5S && features->type <= INTUOSHT) ||
-               (features->type == BAMBOO_PT)) {
+       if ((features->type >= INTUOS5S && features->type <= INTUOSPL) ||
+               (features->type >= INTUOSHT && features->type <= BAMBOO_PT)) {
                if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                        if (features->touch_max)
                                features->device_type |= WACOM_DEVICETYPE_TOUCH;
-                       if (features->type == BAMBOO_PT || features->type == INTUOSHT)
+                       if (features->type >= INTUOSHT || features->type <= BAMBOO_PT)
                                features->device_type |= WACOM_DEVICETYPE_PAD;
 
                        features->x_max = 4096;
@@ -2520,6 +2590,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case CINTIQ:
        case WACOM_13HD:
        case CINTIQ_HYBRID:
+       case CINTIQ_COMPANION_2:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                input_abs_set_res(input_dev, ABS_Z, 287);
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
@@ -2598,16 +2669,22 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
 
        case INTUOSHT:
        case BAMBOO_PT:
-               __clear_bit(ABS_MISC, input_dev->absbit);
-
+       case BAMBOO_PEN:
+       case INTUOSHT2:
                __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-               __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
-               __set_bit(BTN_TOOL_PEN, input_dev->keybit);
-               __set_bit(BTN_STYLUS, input_dev->keybit);
-               __set_bit(BTN_STYLUS2, input_dev->keybit);
-               input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+
+               if (features->type == INTUOSHT2) {
+                       wacom_setup_basic_pro_pen(wacom_wac);
+               } else {
+                       __clear_bit(ABS_MISC, input_dev->absbit);
+                       __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+                       __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+                       __set_bit(BTN_STYLUS, input_dev->keybit);
+                       __set_bit(BTN_STYLUS2, input_dev->keybit);
+                       input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                      features->distance_max,
                                      0, 0);
+               }
                break;
        case BAMBOO_PAD:
                __clear_bit(ABS_MISC, input_dev->absbit);
@@ -2688,11 +2765,13 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                break;
 
        case INTUOSHT:
+       case INTUOSHT2:
                input_dev->evbit[0] |= BIT_MASK(EV_SW);
                __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
                /* fall through */
 
        case BAMBOO_PT:
+       case BAMBOO_TOUCH:
                if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                        input_set_abs_params(input_dev,
                                     ABS_MT_TOUCH_MAJOR,
@@ -2752,6 +2831,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        switch (features->type) {
 
        case CINTIQ_HYBRID:
+       case CINTIQ_COMPANION_2:
        case DTK:
        case DTUS:
        case GRAPHIRE_BT:
@@ -2845,6 +2925,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 
        case INTUOSHT:
        case BAMBOO_PT:
+       case BAMBOO_TOUCH:
+       case INTUOSHT2:
                __clear_bit(ABS_MISC, input_dev->absbit);
 
                __set_bit(BTN_LEFT, input_dev->keybit);
@@ -3235,11 +3317,10 @@ static const struct wacom_features wacom_features_0x47 =
        { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
          INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x84 =
-       { "Wacom Wireless Receiver", 0, 0, 0, 0,
-         WIRELESS, 0, 0, .touch_max = 16 };
+       { "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 };
 static const struct wacom_features wacom_features_0xD0 =
        { "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
+         BAMBOO_TOUCH, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD1 =
        { "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
@@ -3251,10 +3332,10 @@ static const struct wacom_features wacom_features_0xD3 =
          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD4 =
        { "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD5 =
        { "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
        { "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
@@ -3281,7 +3362,7 @@ static const struct wacom_features wacom_features_0xDF =
          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x300 =
        { "Wacom Bamboo One S", 14720, 9225, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x301 =
        { "Wacom Bamboo One M", 21648, 13530, 1023, 31,
          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -3324,14 +3405,38 @@ static const struct wacom_features wacom_features_0x318 =
 static const struct wacom_features wacom_features_0x319 =
        { "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
          .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
+static const struct wacom_features wacom_features_0x325 =
+       { "Wacom ISDv5 325", 59552, 33848, 2047, 63,
+         CINTIQ_COMPANION_2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 11,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x326 };
+static const struct wacom_features wacom_features_0x326 = /* Touch */
+       { "Wacom ISDv5 326", .type = HID_GENERIC, .oVid = USB_VENDOR_ID_WACOM,
+         .oPid = 0x325 };
 static const struct wacom_features wacom_features_0x323 =
        { "Wacom Intuos P M", 21600, 13500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x331 =
-       { "Wacom Express Key Remote", 0, 0, 0, 0,
-         REMOTE, 0, 0, 18, .check_for_hid_type = true,
+       { "Wacom Express Key Remote", .type = REMOTE,
+         .numbered_buttons = 18, .check_for_hid_type = true,
          .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x33B =
+       { "Wacom Intuos S 2", 15200, 9500, 2047, 63,
+         INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x33C =
+       { "Wacom Intuos PT S 2", 15200, 9500, 2047, 63,
+         INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x33D =
+       { "Wacom Intuos P M 2", 21600, 13500, 2047, 63,
+         INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x33E =
+       { "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
+         INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC };
@@ -3483,6 +3588,8 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x318) },
        { USB_DEVICE_WACOM(0x319) },
        { USB_DEVICE_WACOM(0x323) },
+       { USB_DEVICE_WACOM(0x325) },
+       { USB_DEVICE_WACOM(0x326) },
        { USB_DEVICE_WACOM(0x32A) },
        { USB_DEVICE_WACOM(0x32B) },
        { USB_DEVICE_WACOM(0x32C) },
@@ -3491,6 +3598,10 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x333) },
        { USB_DEVICE_WACOM(0x335) },
        { USB_DEVICE_WACOM(0x336) },
+       { USB_DEVICE_WACOM(0x33B) },
+       { USB_DEVICE_WACOM(0x33C) },
+       { USB_DEVICE_WACOM(0x33D) },
+       { USB_DEVICE_WACOM(0x33E) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
index 1e270d401e181e45802cb869d30998d1017ff735..877c24a5df94ad5056983ca95c71bbe79588903f 100644 (file)
@@ -68,6 +68,7 @@
 #define WACOM_REPORT_BPAD_PEN          3
 #define WACOM_REPORT_BPAD_TOUCH                16
 #define WACOM_REPORT_DEVICE_LIST       16
+#define WACOM_REPORT_INTUOS_PEN                16
 #define WACOM_REPORT_REMOTE            17
 
 /* device quirks */
@@ -117,22 +118,26 @@ enum {
        INTUOSPS,
        INTUOSPM,
        INTUOSPL,
-       INTUOSHT,
        WACOM_21UX2,
        WACOM_22HD,
        DTK,
        WACOM_24HD,
        WACOM_27QHD,
        CINTIQ_HYBRID,
+       CINTIQ_COMPANION_2,
        CINTIQ,
        WACOM_BEE,
        WACOM_13HD,
        WACOM_MO,
-       WIRELESS,
+       BAMBOO_PEN,
+       INTUOSHT,
+       INTUOSHT2,
+       BAMBOO_TOUCH,
        BAMBOO_PT,
        WACOM_24HDT,
        WACOM_27QHDT,
        BAMBOO_PAD,
+       WIRELESS,
        REMOTE,
        TABLETPC,   /* add new TPC below */
        TABLETPCE,
@@ -198,6 +203,7 @@ struct hid_data {
        int width;
        int height;
        int id;
+       int cc_report;
        int cc_index;
        int cc_value_index;
        int num_expected;
index 0af63da6b603d05afb5feb23dcf02270905e3470..1f5e956941b1326c6f590b62354bffd40e29ea95 100644 (file)
@@ -1138,7 +1138,7 @@ out:
        return ret;
 }
 
-/* Create accelerometer ressources */
+/* Create accelerometer resources */
 static int applesmc_create_accelerometer(void)
 {
        struct input_dev *idev;
@@ -1191,7 +1191,7 @@ out:
        return ret;
 }
 
-/* Release all ressources used by the accelerometer */
+/* Release all resources used by the accelerometer */
 static void applesmc_release_accelerometer(void)
 {
        if (!smcreg.has_accelerometer)
index f994712d0904733782e6804c20bd7ad47eaffb94..39becbbdfd999b55080aac5856a343ac24f02f2d 100644 (file)
@@ -67,7 +67,7 @@
 #include <linux/acpi.h>
 #include <linux/interrupt.h>
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 /* PCI Address Constants */
 #define SMBBAR         0
index 746cdf56bc76475831cdf39b93a131f24fe804a7..34b1adad07aacf92e9bbfa9621e084f2ec756f74 100644 (file)
@@ -128,7 +128,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
        int ret = -EADDRNOTAVAIL;
 
        if (dev_addr->bound_dev_if) {
-               dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+               dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
                if (!dev)
                        return -ENODEV;
                ret = rdma_copy_addr(dev_addr, dev, NULL);
@@ -138,7 +138,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
 
        switch (addr->sa_family) {
        case AF_INET:
-               dev = ip_dev_find(&init_net,
+               dev = ip_dev_find(dev_addr->net,
                        ((struct sockaddr_in *) addr)->sin_addr.s_addr);
 
                if (!dev)
@@ -149,12 +149,11 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
                        *vlan_id = rdma_vlan_dev_vlan_id(dev);
                dev_put(dev);
                break;
-
 #if IS_ENABLED(CONFIG_IPV6)
        case AF_INET6:
                rcu_read_lock();
-               for_each_netdev_rcu(&init_net, dev) {
-                       if (ipv6_chk_addr(&init_net,
+               for_each_netdev_rcu(dev_addr->net, dev) {
+                       if (ipv6_chk_addr(dev_addr->net,
                                          &((struct sockaddr_in6 *) addr)->sin6_addr,
                                          dev, 1)) {
                                ret = rdma_copy_addr(dev_addr, dev, NULL);
@@ -236,7 +235,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,
        fl4.daddr = dst_ip;
        fl4.saddr = src_ip;
        fl4.flowi4_oif = addr->bound_dev_if;
-       rt = ip_route_output_key(&init_net, &fl4);
+       rt = ip_route_output_key(addr->net, &fl4);
        if (IS_ERR(rt)) {
                ret = PTR_ERR(rt);
                goto out;
@@ -278,12 +277,12 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
        fl6.saddr = src_in->sin6_addr;
        fl6.flowi6_oif = addr->bound_dev_if;
 
-       dst = ip6_route_output(&init_net, NULL, &fl6);
+       dst = ip6_route_output(addr->net, NULL, &fl6);
        if ((ret = dst->error))
                goto put;
 
        if (ipv6_addr_any(&fl6.saddr)) {
-               ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev,
+               ret = ipv6_dev_get_saddr(addr->net, ip6_dst_idev(dst)->dev,
                                         &fl6.daddr, 0, &fl6.saddr);
                if (ret)
                        goto put;
@@ -458,7 +457,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
 }
 
 int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
-                              u8 *dmac, u16 *vlan_id)
+                              u8 *dmac, u16 *vlan_id, int if_index)
 {
        int ret = 0;
        struct rdma_dev_addr dev_addr;
@@ -476,6 +475,8 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
        rdma_gid2ip(&dgid_addr._sockaddr, dgid);
 
        memset(&dev_addr, 0, sizeof(dev_addr));
+       dev_addr.bound_dev_if = if_index;
+       dev_addr.net = &init_net;
 
        ctx.addr = &dev_addr;
        init_completion(&ctx.comp);
@@ -510,6 +511,7 @@ int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id)
        rdma_gid2ip(&gid_addr._sockaddr, sgid);
 
        memset(&dev_addr, 0, sizeof(dev_addr));
+       dev_addr.net = &init_net;
        ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id);
        if (ret)
                return ret;
index 0429040304fd478a7ad7833df48c0bdc74c429bc..4fa524dfb6cf27b1dc958baccba4cb005058f6e8 100644 (file)
@@ -126,7 +126,7 @@ void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *
                mad_send_wr = container_of(send_buf,
                                           struct ib_mad_send_wr_private,
                                           send_buf);
-               mad_send_wr->send_wr.wr.ud.port_num = port_num;
+               mad_send_wr->send_wr.port_num = port_num;
        }
 
        if (ib_post_send_mad(send_buf, NULL)) {
index 87471ef371986c11f59e6761e7566ebec78cc1cd..89bebeada38b9b5f6a09d9dd896c8047fa57d7ad 100644 (file)
@@ -409,10 +409,10 @@ static int ib_cache_gid_find(struct ib_device *ib_dev,
                                        mask, port, index);
 }
 
-int ib_cache_gid_find_by_port(struct ib_device *ib_dev,
-                             const union ib_gid *gid,
-                             u8 port, struct net_device *ndev,
-                             u16 *index)
+int ib_find_cached_gid_by_port(struct ib_device *ib_dev,
+                              const union ib_gid *gid,
+                              u8 port, struct net_device *ndev,
+                              u16 *index)
 {
        int local_index;
        struct ib_gid_table **ports_table = ib_dev->cache.gid_cache;
@@ -438,6 +438,82 @@ int ib_cache_gid_find_by_port(struct ib_device *ib_dev,
 
        return -ENOENT;
 }
+EXPORT_SYMBOL(ib_find_cached_gid_by_port);
+
+/**
+ * ib_find_gid_by_filter - Returns the GID table index where a specified
+ * GID value occurs
+ * @device: The device to query.
+ * @gid: The GID value to search for.
+ * @port_num: The port number of the device where the GID value could be
+ *   searched.
+ * @filter: The filter function is executed on any matching GID in the table.
+ *   If the filter function returns true, the corresponding index is returned,
+ *   otherwise, we continue searching the GID table. It's guaranteed that
+ *   while filter is executed, ndev field is valid and the structure won't
+ *   change. filter is executed in an atomic context. filter must not be NULL.
+ * @index: The index into the cached GID table where the GID was found.  This
+ *   parameter may be NULL.
+ *
+ * ib_cache_gid_find_by_filter() searches for the specified GID value
+ * of which the filter function returns true in the port's GID table.
+ * This function is only supported on RoCE ports.
+ *
+ */
+static int ib_cache_gid_find_by_filter(struct ib_device *ib_dev,
+                                      const union ib_gid *gid,
+                                      u8 port,
+                                      bool (*filter)(const union ib_gid *,
+                                                     const struct ib_gid_attr *,
+                                                     void *),
+                                      void *context,
+                                      u16 *index)
+{
+       struct ib_gid_table **ports_table = ib_dev->cache.gid_cache;
+       struct ib_gid_table *table;
+       unsigned int i;
+       bool found = false;
+
+       if (!ports_table)
+               return -EOPNOTSUPP;
+
+       if (port < rdma_start_port(ib_dev) ||
+           port > rdma_end_port(ib_dev) ||
+           !rdma_protocol_roce(ib_dev, port))
+               return -EPROTONOSUPPORT;
+
+       table = ports_table[port - rdma_start_port(ib_dev)];
+
+       for (i = 0; i < table->sz; i++) {
+               struct ib_gid_attr attr;
+               unsigned long flags;
+
+               read_lock_irqsave(&table->data_vec[i].lock, flags);
+               if (table->data_vec[i].props & GID_TABLE_ENTRY_INVALID)
+                       goto next;
+
+               if (memcmp(gid, &table->data_vec[i].gid, sizeof(*gid)))
+                       goto next;
+
+               memcpy(&attr, &table->data_vec[i].attr, sizeof(attr));
+
+               if (filter(gid, &attr, context))
+                       found = true;
+
+next:
+               read_unlock_irqrestore(&table->data_vec[i].lock, flags);
+
+               if (found)
+                       break;
+       }
+
+       if (!found)
+               return -ENOENT;
+
+       if (index)
+               *index = i;
+       return 0;
+}
 
 static struct ib_gid_table *alloc_gid_table(int sz)
 {
@@ -649,24 +725,44 @@ static int gid_table_setup_one(struct ib_device *ib_dev)
 int ib_get_cached_gid(struct ib_device *device,
                      u8                port_num,
                      int               index,
-                     union ib_gid     *gid)
+                     union ib_gid     *gid,
+                     struct ib_gid_attr *gid_attr)
 {
        if (port_num < rdma_start_port(device) || port_num > rdma_end_port(device))
                return -EINVAL;
 
-       return __ib_cache_gid_get(device, port_num, index, gid, NULL);
+       return __ib_cache_gid_get(device, port_num, index, gid, gid_attr);
 }
 EXPORT_SYMBOL(ib_get_cached_gid);
 
 int ib_find_cached_gid(struct ib_device *device,
                       const union ib_gid *gid,
+                      struct net_device *ndev,
                       u8               *port_num,
                       u16              *index)
 {
-       return ib_cache_gid_find(device, gid, NULL, port_num, index);
+       return ib_cache_gid_find(device, gid, ndev, port_num, index);
 }
 EXPORT_SYMBOL(ib_find_cached_gid);
 
+int ib_find_gid_by_filter(struct ib_device *device,
+                         const union ib_gid *gid,
+                         u8 port_num,
+                         bool (*filter)(const union ib_gid *gid,
+                                        const struct ib_gid_attr *,
+                                        void *),
+                         void *context, u16 *index)
+{
+       /* Only RoCE GID table supports filter function */
+       if (!rdma_cap_roce_gid_table(device, port_num) && filter)
+               return -EPROTONOSUPPORT;
+
+       return ib_cache_gid_find_by_filter(device, gid,
+                                          port_num, filter,
+                                          context, index);
+}
+EXPORT_SYMBOL(ib_find_gid_by_filter);
+
 int ib_get_cached_pkey(struct ib_device *device,
                       u8                port_num,
                       int               index,
@@ -845,7 +941,7 @@ static void ib_cache_update(struct ib_device *device,
        if (!use_roce_gid_table) {
                for (i = 0;  i < gid_cache->table_len; ++i) {
                        ret = ib_query_gid(device, port, i,
-                                          gid_cache->table + i);
+                                          gid_cache->table + i, NULL);
                        if (ret) {
                                printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n",
                                       ret, device->name, i);
index 4f918b929eca955532cd5dc0541bc842272a0a3b..0a26dd6d9b19f96d97c9b3b244509892afae7023 100644 (file)
@@ -179,8 +179,6 @@ struct cm_av {
        struct ib_ah_attr ah_attr;
        u16 pkey_index;
        u8 timeout;
-       u8  valid;
-       u8  smac[ETH_ALEN];
 };
 
 struct cm_work {
@@ -361,17 +359,21 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
        unsigned long flags;
        int ret;
        u8 p;
+       struct net_device *ndev = ib_get_ndev_from_path(path);
 
        read_lock_irqsave(&cm.device_lock, flags);
        list_for_each_entry(cm_dev, &cm.device_list, list) {
                if (!ib_find_cached_gid(cm_dev->ib_device, &path->sgid,
-                                       &p, NULL)) {
+                                       ndev, &p, NULL)) {
                        port = cm_dev->port[p-1];
                        break;
                }
        }
        read_unlock_irqrestore(&cm.device_lock, flags);
 
+       if (ndev)
+               dev_put(ndev);
+
        if (!port)
                return -EINVAL;
 
@@ -384,9 +386,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
        ib_init_ah_from_path(cm_dev->ib_device, port->port_num, path,
                             &av->ah_attr);
        av->timeout = path->packet_life_time + 1;
-       memcpy(av->smac, path->smac, sizeof(av->smac));
 
-       av->valid = 1;
        return 0;
 }
 
@@ -1639,11 +1639,11 @@ static int cm_req_handler(struct cm_work *work)
        cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
 
        memcpy(work->path[0].dmac, cm_id_priv->av.ah_attr.dmac, ETH_ALEN);
-       work->path[0].vlan_id = cm_id_priv->av.ah_attr.vlan_id;
        ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
        if (ret) {
                ib_get_cached_gid(work->port->cm_dev->ib_device,
-                                 work->port->port_num, 0, &work->path[0].sgid);
+                                 work->port->port_num, 0, &work->path[0].sgid,
+                                 NULL);
                ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
                               &work->path[0].sgid, sizeof work->path[0].sgid,
                               NULL, 0);
@@ -3618,32 +3618,6 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
                *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU |
                                IB_QP_DEST_QPN | IB_QP_RQ_PSN;
                qp_attr->ah_attr = cm_id_priv->av.ah_attr;
-               if (!cm_id_priv->av.valid) {
-                       spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-                       return -EINVAL;
-               }
-               if (cm_id_priv->av.ah_attr.vlan_id != 0xffff) {
-                       qp_attr->vlan_id = cm_id_priv->av.ah_attr.vlan_id;
-                       *qp_attr_mask |= IB_QP_VID;
-               }
-               if (!is_zero_ether_addr(cm_id_priv->av.smac)) {
-                       memcpy(qp_attr->smac, cm_id_priv->av.smac,
-                              sizeof(qp_attr->smac));
-                       *qp_attr_mask |= IB_QP_SMAC;
-               }
-               if (cm_id_priv->alt_av.valid) {
-                       if (cm_id_priv->alt_av.ah_attr.vlan_id != 0xffff) {
-                               qp_attr->alt_vlan_id =
-                                       cm_id_priv->alt_av.ah_attr.vlan_id;
-                               *qp_attr_mask |= IB_QP_ALT_VID;
-                       }
-                       if (!is_zero_ether_addr(cm_id_priv->alt_av.smac)) {
-                               memcpy(qp_attr->alt_smac,
-                                      cm_id_priv->alt_av.smac,
-                                      sizeof(qp_attr->alt_smac));
-                               *qp_attr_mask |= IB_QP_ALT_SMAC;
-                       }
-               }
                qp_attr->path_mtu = cm_id_priv->path_mtu;
                qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn);
                qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn);
index 36b12d560e17e5a862a2e37d1f56875b46425f4b..944cd90417bcc9b2a51d27f903feffad6f2307ea 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/module.h>
 #include <net/route.h>
 
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip_fib.h>
@@ -86,7 +88,7 @@ static const char * const cma_events[] = {
        [RDMA_CM_EVENT_TIMEWAIT_EXIT]    = "timewait exit",
 };
 
-const char *rdma_event_msg(enum rdma_cm_event_type event)
+const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
 {
        size_t index = event;
 
@@ -110,22 +112,33 @@ static LIST_HEAD(dev_list);
 static LIST_HEAD(listen_any_list);
 static DEFINE_MUTEX(lock);
 static struct workqueue_struct *cma_wq;
-static DEFINE_IDR(tcp_ps);
-static DEFINE_IDR(udp_ps);
-static DEFINE_IDR(ipoib_ps);
-static DEFINE_IDR(ib_ps);
+static int cma_pernet_id;
 
-static struct idr *cma_idr(enum rdma_port_space ps)
+struct cma_pernet {
+       struct idr tcp_ps;
+       struct idr udp_ps;
+       struct idr ipoib_ps;
+       struct idr ib_ps;
+};
+
+static struct cma_pernet *cma_pernet(struct net *net)
+{
+       return net_generic(net, cma_pernet_id);
+}
+
+static struct idr *cma_pernet_idr(struct net *net, enum rdma_port_space ps)
 {
+       struct cma_pernet *pernet = cma_pernet(net);
+
        switch (ps) {
        case RDMA_PS_TCP:
-               return &tcp_ps;
+               return &pernet->tcp_ps;
        case RDMA_PS_UDP:
-               return &udp_ps;
+               return &pernet->udp_ps;
        case RDMA_PS_IPOIB:
-               return &ipoib_ps;
+               return &pernet->ipoib_ps;
        case RDMA_PS_IB:
-               return &ib_ps;
+               return &pernet->ib_ps;
        default:
                return NULL;
        }
@@ -145,24 +158,25 @@ struct rdma_bind_list {
        unsigned short          port;
 };
 
-static int cma_ps_alloc(enum rdma_port_space ps,
+static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
                        struct rdma_bind_list *bind_list, int snum)
 {
-       struct idr *idr = cma_idr(ps);
+       struct idr *idr = cma_pernet_idr(net, ps);
 
        return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL);
 }
 
-static struct rdma_bind_list *cma_ps_find(enum rdma_port_space ps, int snum)
+static struct rdma_bind_list *cma_ps_find(struct net *net,
+                                         enum rdma_port_space ps, int snum)
 {
-       struct idr *idr = cma_idr(ps);
+       struct idr *idr = cma_pernet_idr(net, ps);
 
        return idr_find(idr, snum);
 }
 
-static void cma_ps_remove(enum rdma_port_space ps, int snum)
+static void cma_ps_remove(struct net *net, enum rdma_port_space ps, int snum)
 {
-       struct idr *idr = cma_idr(ps);
+       struct idr *idr = cma_pernet_idr(net, ps);
 
        idr_remove(idr, snum);
 }
@@ -427,10 +441,11 @@ static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_a
 }
 
 static inline int cma_validate_port(struct ib_device *device, u8 port,
-                                     union ib_gid *gid, int dev_type)
+                                     union ib_gid *gid, int dev_type,
+                                     int bound_if_index)
 {
-       u8 found_port;
        int ret = -ENODEV;
+       struct net_device *ndev = NULL;
 
        if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port))
                return ret;
@@ -438,9 +453,13 @@ static inline int cma_validate_port(struct ib_device *device, u8 port,
        if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
                return ret;
 
-       ret = ib_find_cached_gid(device, gid, &found_port, NULL);
-       if (port != found_port)
-               return -ENODEV;
+       if (dev_type == ARPHRD_ETHER)
+               ndev = dev_get_by_index(&init_net, bound_if_index);
+
+       ret = ib_find_cached_gid_by_port(device, gid, port, ndev, NULL);
+
+       if (ndev)
+               dev_put(ndev);
 
        return ret;
 }
@@ -472,7 +491,8 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv,
                       &iboe_gid : &gid;
 
                ret = cma_validate_port(cma_dev->device, port, gidp,
-                                       dev_addr->dev_type);
+                                       dev_addr->dev_type,
+                                       dev_addr->bound_dev_if);
                if (!ret) {
                        id_priv->id.port_num = port;
                        goto out;
@@ -490,7 +510,8 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv,
                               &iboe_gid : &gid;
 
                        ret = cma_validate_port(cma_dev->device, port, gidp,
-                                               dev_addr->dev_type);
+                                               dev_addr->dev_type,
+                                               dev_addr->bound_dev_if);
                        if (!ret) {
                                id_priv->id.port_num = port;
                                goto out;
@@ -531,7 +552,9 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                        if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
                                continue;
 
-                       for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i, &gid); i++) {
+                       for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i,
+                                                      &gid, NULL);
+                            i++) {
                                if (!memcmp(&gid, dgid, sizeof(gid))) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
@@ -577,7 +600,8 @@ static int cma_disable_callback(struct rdma_id_private *id_priv,
        return 0;
 }
 
-struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+struct rdma_cm_id *rdma_create_id(struct net *net,
+                                 rdma_cm_event_handler event_handler,
                                  void *context, enum rdma_port_space ps,
                                  enum ib_qp_type qp_type)
 {
@@ -601,6 +625,7 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
        INIT_LIST_HEAD(&id_priv->listen_list);
        INIT_LIST_HEAD(&id_priv->mc_list);
        get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
+       id_priv->id.route.addr.dev_addr.net = get_net(net);
 
        return &id_priv->id;
 }
@@ -718,18 +743,12 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
                goto out;
 
        ret = ib_query_gid(id_priv->id.device, id_priv->id.port_num,
-                          qp_attr.ah_attr.grh.sgid_index, &sgid);
+                          qp_attr.ah_attr.grh.sgid_index, &sgid, NULL);
        if (ret)
                goto out;
 
        BUG_ON(id_priv->cma_dev->device != id_priv->id.device);
 
-       if (rdma_protocol_roce(id_priv->id.device, id_priv->id.port_num)) {
-               ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr.smac, NULL);
-
-               if (ret)
-                       goto out;
-       }
        if (conn_param)
                qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
        ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
@@ -1260,7 +1279,7 @@ static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
                       cma_protocol_roce(&id_priv->id);
 
        return !addr->dev_addr.bound_dev_if ||
-              (net_eq(dev_net(net_dev), &init_net) &&
+              (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
                addr->dev_addr.bound_dev_if == net_dev->ifindex);
 }
 
@@ -1321,7 +1340,8 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
                }
        }
 
-       bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id),
+       bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net,
+                               rdma_ps_from_service_id(req.service_id),
                                cma_port_from_service_id(req.service_id));
        id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev);
        if (IS_ERR(id_priv) && *net_dev) {
@@ -1392,6 +1412,7 @@ static void cma_cancel_operation(struct rdma_id_private *id_priv,
 static void cma_release_port(struct rdma_id_private *id_priv)
 {
        struct rdma_bind_list *bind_list = id_priv->bind_list;
+       struct net *net = id_priv->id.route.addr.dev_addr.net;
 
        if (!bind_list)
                return;
@@ -1399,7 +1420,7 @@ static void cma_release_port(struct rdma_id_private *id_priv)
        mutex_lock(&lock);
        hlist_del(&id_priv->node);
        if (hlist_empty(&bind_list->owners)) {
-               cma_ps_remove(bind_list->ps, bind_list->port);
+               cma_ps_remove(net, bind_list->ps, bind_list->port);
                kfree(bind_list);
        }
        mutex_unlock(&lock);
@@ -1458,6 +1479,7 @@ void rdma_destroy_id(struct rdma_cm_id *id)
                cma_deref_id(id_priv->id.context);
 
        kfree(id_priv->id.route.path_rec);
+       put_net(id_priv->id.route.addr.dev_addr.net);
        kfree(id_priv);
 }
 EXPORT_SYMBOL(rdma_destroy_id);
@@ -1588,7 +1610,8 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
                      ib_event->param.req_rcvd.primary_path->service_id;
        int ret;
 
-       id = rdma_create_id(listen_id->event_handler, listen_id->context,
+       id = rdma_create_id(listen_id->route.addr.dev_addr.net,
+                           listen_id->event_handler, listen_id->context,
                            listen_id->ps, ib_event->param.req_rcvd.qp_type);
        if (IS_ERR(id))
                return NULL;
@@ -1643,9 +1666,10 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        struct rdma_id_private *id_priv;
        struct rdma_cm_id *id;
        const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family;
+       struct net *net = listen_id->route.addr.dev_addr.net;
        int ret;
 
-       id = rdma_create_id(listen_id->event_handler, listen_id->context,
+       id = rdma_create_id(net, listen_id->event_handler, listen_id->context,
                            listen_id->ps, IB_QPT_UD);
        if (IS_ERR(id))
                return NULL;
@@ -1882,7 +1906,8 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
                return -ECONNABORTED;
 
        /* Create a new RDMA id for the new IW CM ID */
-       new_cm_id = rdma_create_id(listen_id->id.event_handler,
+       new_cm_id = rdma_create_id(listen_id->id.route.addr.dev_addr.net,
+                                  listen_id->id.event_handler,
                                   listen_id->id.context,
                                   RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(new_cm_id)) {
@@ -2010,12 +2035,13 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
 {
        struct rdma_id_private *dev_id_priv;
        struct rdma_cm_id *id;
+       struct net *net = id_priv->id.route.addr.dev_addr.net;
        int ret;
 
        if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
                return;
 
-       id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
+       id = rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps,
                            id_priv->id.qp_type);
        if (IS_ERR(id))
                return;
@@ -2294,16 +2320,17 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
 
        route->num_paths = 1;
 
-       if (addr->dev_addr.bound_dev_if)
+       if (addr->dev_addr.bound_dev_if) {
                ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
+               route->path_rec->net = &init_net;
+               route->path_rec->ifindex = addr->dev_addr.bound_dev_if;
+       }
        if (!ndev) {
                ret = -ENODEV;
                goto err2;
        }
 
-       route->path_rec->vlan_id = rdma_vlan_dev_vlan_id(ndev);
        memcpy(route->path_rec->dmac, addr->dev_addr.dst_dev_addr, ETH_ALEN);
-       memcpy(route->path_rec->smac, ndev->dev_addr, ndev->addr_len);
 
        rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
                    &route->path_rec->sgid);
@@ -2426,7 +2453,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
        p = 1;
 
 port_found:
-       ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
+       ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid, NULL);
        if (ret)
                goto out;
 
@@ -2688,7 +2715,8 @@ static int cma_alloc_port(enum rdma_port_space ps,
        if (!bind_list)
                return -ENOMEM;
 
-       ret = cma_ps_alloc(ps, bind_list, snum);
+       ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list,
+                          snum);
        if (ret < 0)
                goto err;
 
@@ -2707,13 +2735,14 @@ static int cma_alloc_any_port(enum rdma_port_space ps,
        static unsigned int last_used_port;
        int low, high, remaining;
        unsigned int rover;
+       struct net *net = id_priv->id.route.addr.dev_addr.net;
 
-       inet_get_local_port_range(&init_net, &low, &high);
+       inet_get_local_port_range(net, &low, &high);
        remaining = (high - low) + 1;
        rover = prandom_u32() % remaining + low;
 retry:
        if (last_used_port != rover &&
-           !cma_ps_find(ps, (unsigned short)rover)) {
+           !cma_ps_find(net, ps, (unsigned short)rover)) {
                int ret = cma_alloc_port(ps, id_priv, rover);
                /*
                 * Remember previously used port number in order to avoid
@@ -2779,7 +2808,7 @@ static int cma_use_port(enum rdma_port_space ps,
        if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
-       bind_list = cma_ps_find(ps, snum);
+       bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum);
        if (!bind_list) {
                ret = cma_alloc_port(ps, id_priv, snum);
        } else {
@@ -2971,8 +3000,11 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                if (addr->sa_family == AF_INET)
                        id_priv->afonly = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-               else if (addr->sa_family == AF_INET6)
-                       id_priv->afonly = init_net.ipv6.sysctl.bindv6only;
+               else if (addr->sa_family == AF_INET6) {
+                       struct net *net = id_priv->id.route.addr.dev_addr.net;
+
+                       id_priv->afonly = net->ipv6.sysctl.bindv6only;
+               }
 #endif
        }
        ret = cma_get_port(id_priv);
@@ -3777,6 +3809,7 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id
        dev_addr = &id_priv->id.route.addr.dev_addr;
 
        if ((dev_addr->bound_dev_if == ndev->ifindex) &&
+           (net_eq(dev_net(ndev), dev_addr->net)) &&
            memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
                printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n",
                       ndev->name, &id_priv->id);
@@ -3802,9 +3835,6 @@ static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
        struct rdma_id_private *id_priv;
        int ret = NOTIFY_DONE;
 
-       if (dev_net(ndev) != &init_net)
-               return NOTIFY_DONE;
-
        if (event != NETDEV_BONDING_FAILOVER)
                return NOTIFY_DONE;
 
@@ -3999,6 +4029,35 @@ static const struct ibnl_client_cbs cma_cb_table[] = {
                                       .module = THIS_MODULE },
 };
 
+static int cma_init_net(struct net *net)
+{
+       struct cma_pernet *pernet = cma_pernet(net);
+
+       idr_init(&pernet->tcp_ps);
+       idr_init(&pernet->udp_ps);
+       idr_init(&pernet->ipoib_ps);
+       idr_init(&pernet->ib_ps);
+
+       return 0;
+}
+
+static void cma_exit_net(struct net *net)
+{
+       struct cma_pernet *pernet = cma_pernet(net);
+
+       idr_destroy(&pernet->tcp_ps);
+       idr_destroy(&pernet->udp_ps);
+       idr_destroy(&pernet->ipoib_ps);
+       idr_destroy(&pernet->ib_ps);
+}
+
+static struct pernet_operations cma_pernet_operations = {
+       .init = cma_init_net,
+       .exit = cma_exit_net,
+       .id = &cma_pernet_id,
+       .size = sizeof(struct cma_pernet),
+};
+
 static int __init cma_init(void)
 {
        int ret;
@@ -4007,6 +4066,10 @@ static int __init cma_init(void)
        if (!cma_wq)
                return -ENOMEM;
 
+       ret = register_pernet_subsys(&cma_pernet_operations);
+       if (ret)
+               goto err_wq;
+
        ib_sa_register_client(&sa_client);
        rdma_addr_register_client(&addr_client);
        register_netdevice_notifier(&cma_nb);
@@ -4024,6 +4087,7 @@ err:
        unregister_netdevice_notifier(&cma_nb);
        rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
+err_wq:
        destroy_workqueue(cma_wq);
        return ret;
 }
@@ -4035,11 +4099,8 @@ static void __exit cma_cleanup(void)
        unregister_netdevice_notifier(&cma_nb);
        rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
+       unregister_pernet_subsys(&cma_pernet_operations);
        destroy_workqueue(cma_wq);
-       idr_destroy(&tcp_ps);
-       idr_destroy(&udp_ps);
-       idr_destroy(&ipoib_ps);
-       idr_destroy(&ib_ps);
 }
 
 module_init(cma_init);
index 70bb36ebb03b8e91ff2cf89445b0a8f52329e591..5cf6eb716f000a7aa07233419a0dcbbce41e0b6d 100644 (file)
@@ -46,8 +46,8 @@ void ib_device_unregister_sysfs(struct ib_device *device);
 void ib_cache_setup(void);
 void ib_cache_cleanup(void);
 
-int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
-                           struct ib_qp_attr *qp_attr, int *qp_attr_mask);
+int ib_resolve_eth_dmac(struct ib_qp *qp,
+                       struct ib_qp_attr *qp_attr, int *qp_attr_mask);
 
 typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port,
              struct net_device *idev, void *cookie);
@@ -65,11 +65,6 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
                              roce_netdev_callback cb,
                              void *cookie);
 
-int ib_cache_gid_find_by_port(struct ib_device *ib_dev,
-                             const union ib_gid *gid,
-                             u8 port, struct net_device *ndev,
-                             u16 *index);
-
 enum ib_cache_gid_default_mode {
        IB_CACHE_GID_DEFAULT_MODE_SET,
        IB_CACHE_GID_DEFAULT_MODE_DELETE
index 17639117afc6ab8637c7e73a3e2a13e6101a9702..179e8134d57fc13b425254d5162006f9fc201879 100644 (file)
@@ -672,14 +672,20 @@ EXPORT_SYMBOL(ib_query_port);
  * @port_num:Port number to query
  * @index:GID table index to query
  * @gid:Returned GID
+ * @attr: Returned GID attributes related to this GID index (only in RoCE).
+ *   NULL means ignore.
  *
  * ib_query_gid() fetches the specified GID table entry.
  */
 int ib_query_gid(struct ib_device *device,
-                u8 port_num, int index, union ib_gid *gid)
+                u8 port_num, int index, union ib_gid *gid,
+                struct ib_gid_attr *attr)
 {
        if (rdma_cap_roce_gid_table(device, port_num))
-               return ib_get_cached_gid(device, port_num, index, gid);
+               return ib_get_cached_gid(device, port_num, index, gid, attr);
+
+       if (attr)
+               return -EINVAL;
 
        return device->query_gid(device, port_num, index, gid);
 }
@@ -819,27 +825,28 @@ EXPORT_SYMBOL(ib_modify_port);
  *   a specified GID value occurs.
  * @device: The device to query.
  * @gid: The GID value to search for.
+ * @ndev: The ndev related to the GID to search for.
  * @port_num: The port number of the device where the GID value was found.
  * @index: The index into the GID table where the GID was found.  This
  *   parameter may be NULL.
  */
 int ib_find_gid(struct ib_device *device, union ib_gid *gid,
-               u8 *port_num, u16 *index)
+               struct net_device *ndev, u8 *port_num, u16 *index)
 {
        union ib_gid tmp_gid;
        int ret, port, i;
 
        for (port = rdma_start_port(device); port <= rdma_end_port(device); ++port) {
                if (rdma_cap_roce_gid_table(device, port)) {
-                       if (!ib_cache_gid_find_by_port(device, gid, port,
-                                                      NULL, index)) {
+                       if (!ib_find_cached_gid_by_port(device, gid, port,
+                                                       ndev, index)) {
                                *port_num = port;
                                return 0;
                        }
                }
 
                for (i = 0; i < device->port_immutable[port].gid_tbl_len; ++i) {
-                       ret = ib_query_gid(device, port, i, &tmp_gid);
+                       ret = ib_query_gid(device, port, i, &tmp_gid, NULL);
                        if (ret)
                                return ret;
                        if (!memcmp(&tmp_gid, gid, sizeof *gid)) {
index 4b5c72311debbe59ae0975ec6d0fa722db13234e..8d8af7a41a30fae4ceb520ce0d11b6f541905c96 100644 (file)
@@ -752,7 +752,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
        struct ib_device *device = mad_agent_priv->agent.device;
        u8 port_num;
        struct ib_wc mad_wc;
-       struct ib_send_wr *send_wr = &mad_send_wr->send_wr;
+       struct ib_ud_wr *send_wr = &mad_send_wr->send_wr;
        size_t mad_size = port_mad_size(mad_agent_priv->qp_info->port_priv);
        u16 out_mad_pkey_index = 0;
        u16 drslid;
@@ -761,7 +761,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
 
        if (rdma_cap_ib_switch(device) &&
            smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
-               port_num = send_wr->wr.ud.port_num;
+               port_num = send_wr->port_num;
        else
                port_num = mad_agent_priv->agent.port_num;
 
@@ -832,9 +832,9 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
        }
 
        build_smp_wc(mad_agent_priv->agent.qp,
-                    send_wr->wr_id, drslid,
-                    send_wr->wr.ud.pkey_index,
-                    send_wr->wr.ud.port_num, &mad_wc);
+                    send_wr->wr.wr_id, drslid,
+                    send_wr->pkey_index,
+                    send_wr->port_num, &mad_wc);
 
        if (opa && smp->base_version == OPA_MGMT_BASE_VERSION) {
                mad_wc.byte_len = mad_send_wr->send_buf.hdr_len
@@ -894,7 +894,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
 
        local->mad_send_wr = mad_send_wr;
        if (opa) {
-               local->mad_send_wr->send_wr.wr.ud.pkey_index = out_mad_pkey_index;
+               local->mad_send_wr->send_wr.pkey_index = out_mad_pkey_index;
                local->return_wc_byte_len = mad_size;
        }
        /* Reference MAD agent until send side of local completion handled */
@@ -1039,14 +1039,14 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
 
        mad_send_wr->sg_list[1].lkey = mad_agent->qp->pd->local_dma_lkey;
 
-       mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr;
-       mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list;
-       mad_send_wr->send_wr.num_sge = 2;
-       mad_send_wr->send_wr.opcode = IB_WR_SEND;
-       mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED;
-       mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn;
-       mad_send_wr->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY;
-       mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index;
+       mad_send_wr->send_wr.wr.wr_id = (unsigned long) mad_send_wr;
+       mad_send_wr->send_wr.wr.sg_list = mad_send_wr->sg_list;
+       mad_send_wr->send_wr.wr.num_sge = 2;
+       mad_send_wr->send_wr.wr.opcode = IB_WR_SEND;
+       mad_send_wr->send_wr.wr.send_flags = IB_SEND_SIGNALED;
+       mad_send_wr->send_wr.remote_qpn = remote_qpn;
+       mad_send_wr->send_wr.remote_qkey = IB_QP_SET_QKEY;
+       mad_send_wr->send_wr.pkey_index = pkey_index;
 
        if (rmpp_active) {
                ret = alloc_send_rmpp_list(mad_send_wr, mad_size, gfp_mask);
@@ -1151,7 +1151,7 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
 
        /* Set WR ID to find mad_send_wr upon completion */
        qp_info = mad_send_wr->mad_agent_priv->qp_info;
-       mad_send_wr->send_wr.wr_id = (unsigned long)&mad_send_wr->mad_list;
+       mad_send_wr->send_wr.wr.wr_id = (unsigned long)&mad_send_wr->mad_list;
        mad_send_wr->mad_list.mad_queue = &qp_info->send_queue;
 
        mad_agent = mad_send_wr->send_buf.mad_agent;
@@ -1179,7 +1179,7 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
 
        spin_lock_irqsave(&qp_info->send_queue.lock, flags);
        if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
-               ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr,
+               ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr.wr,
                                   &bad_send_wr);
                list = &qp_info->send_queue.list;
        } else {
@@ -1244,7 +1244,7 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
                 * request associated with the completion
                 */
                next_send_buf = send_buf->next;
-               mad_send_wr->send_wr.wr.ud.ah = send_buf->ah;
+               mad_send_wr->send_wr.ah = send_buf->ah;
 
                if (((struct ib_mad_hdr *) send_buf->mad)->mgmt_class ==
                    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
@@ -1877,7 +1877,7 @@ static inline int rcv_has_same_gid(const struct ib_mad_agent_private *mad_agent_
                                          ((1 << lmc) - 1)));
                } else {
                        if (ib_get_cached_gid(device, port_num,
-                                             attr.grh.sgid_index, &sgid))
+                                             attr.grh.sgid_index, &sgid, NULL))
                                return 0;
                        return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw,
                                       16);
@@ -2457,7 +2457,7 @@ retry:
        ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc);
 
        if (queued_send_wr) {
-               ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr,
+               ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr.wr,
                                   &bad_send_wr);
                if (ret) {
                        dev_err(&port_priv->device->dev,
@@ -2515,7 +2515,7 @@ static void mad_error_handler(struct ib_mad_port_private *port_priv,
                        struct ib_send_wr *bad_send_wr;
 
                        mad_send_wr->retry = 0;
-                       ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr,
+                       ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr.wr,
                                        &bad_send_wr);
                        if (ret)
                                ib_mad_send_done_handler(port_priv, wc);
@@ -2713,7 +2713,7 @@ static void local_completions(struct work_struct *work)
                        build_smp_wc(recv_mad_agent->agent.qp,
                                     (unsigned long) local->mad_send_wr,
                                     be16_to_cpu(IB_LID_PERMISSIVE),
-                                    local->mad_send_wr->send_wr.wr.ud.pkey_index,
+                                    local->mad_send_wr->send_wr.pkey_index,
                                     recv_mad_agent->agent.port_num, &wc);
 
                        local->mad_priv->header.recv_wc.wc = &wc;
index 4a4f7aad09783de0cfd3fb92031b03890925b760..990698a6ab4b7024116ae50c9417d00ce179b41c 100644 (file)
@@ -123,7 +123,7 @@ struct ib_mad_send_wr_private {
        struct ib_mad_send_buf send_buf;
        u64 header_mapping;
        u64 payload_mapping;
-       struct ib_send_wr send_wr;
+       struct ib_ud_wr send_wr;
        struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
        __be64 tid;
        unsigned long timeout;
index d38d8b2b2979ddc2bebb243b98b79a04644fc929..bb6685fb08c61483546505f99037b88af6202ad0 100644 (file)
@@ -729,7 +729,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
        u16 gid_index;
        u8 p;
 
-       ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index);
+       ret = ib_find_cached_gid(device, &rec->port_gid,
+                                NULL, &p, &gid_index);
        if (ret)
                return ret;
 
index 59ab264c99c4f4a87c92cf654f14cc0806539cd6..2aba774f835b9caca8e9e1645d1efd6cf6f08bf9 100644 (file)
@@ -1007,26 +1007,29 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
        force_grh = rdma_cap_eth_ah(device, port_num);
 
        if (rec->hop_limit > 1 || force_grh) {
+               struct net_device *ndev = ib_get_ndev_from_path(rec);
+
                ah_attr->ah_flags = IB_AH_GRH;
                ah_attr->grh.dgid = rec->dgid;
 
-               ret = ib_find_cached_gid(device, &rec->sgid, &port_num,
+               ret = ib_find_cached_gid(device, &rec->sgid, ndev, &port_num,
                                         &gid_index);
-               if (ret)
+               if (ret) {
+                       if (ndev)
+                               dev_put(ndev);
                        return ret;
+               }
 
                ah_attr->grh.sgid_index    = gid_index;
                ah_attr->grh.flow_label    = be32_to_cpu(rec->flow_label);
                ah_attr->grh.hop_limit     = rec->hop_limit;
                ah_attr->grh.traffic_class = rec->traffic_class;
+               if (ndev)
+                       dev_put(ndev);
        }
        if (force_grh) {
                memcpy(ah_attr->dmac, rec->dmac, ETH_ALEN);
-               ah_attr->vlan_id = rec->vlan_id;
-       } else {
-               ah_attr->vlan_id = 0xffff;
        }
-
        return 0;
 }
 EXPORT_SYMBOL(ib_init_ah_from_path);
@@ -1150,9 +1153,9 @@ static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
 
                ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
                          mad->data, &rec);
-               rec.vlan_id = 0xffff;
+               rec.net = NULL;
+               rec.ifindex = 0;
                memset(rec.dmac, 0, ETH_ALEN);
-               memset(rec.smac, 0, ETH_ALEN);
                query->callback(status, &rec, query->context);
        } else
                query->callback(status, NULL, query->context);
index 34cdd74b0a17ed06228bf78f134c2001c976125a..b1f37d4095fa1e15f7402c35a367b00e1f24b6b5 100644 (file)
@@ -289,7 +289,7 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
        union ib_gid gid;
        ssize_t ret;
 
-       ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid);
+       ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid, NULL);
        if (ret)
                return ret;
 
index 30467d10df91b170e40657864354356153545e76..8b5a934e1133d80b42e12d1790b3672d73e4a779 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 #include <linux/module.h>
+#include <linux/nsproxy.h>
 
 #include <rdma/rdma_user_cm.h>
 #include <rdma/ib_marshall.h>
@@ -472,7 +473,8 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
                return -ENOMEM;
 
        ctx->uid = cmd.uid;
-       ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
+       ctx->cm_id = rdma_create_id(current->nsproxy->net_ns,
+                                   ucma_event_handler, ctx, cmd.ps, qp_type);
        if (IS_ERR(ctx->cm_id)) {
                ret = PTR_ERR(ctx->cm_id);
                goto err1;
@@ -1211,7 +1213,6 @@ static int ucma_set_ib_path(struct ucma_context *ctx,
                return -EINVAL;
 
        memset(&sa_path, 0, sizeof(sa_path));
-       sa_path.vlan_id = 0xffff;
 
        ib_sa_unpack_path(path_data->path_rec, &sa_path);
        ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
index 3863d33c243d80cde7df7c100205d4578aa58d7a..94bbd8c155fcca1daf5f2e9ee0fc65552821ff3f 100644 (file)
@@ -272,5 +272,6 @@ IB_UVERBS_DECLARE_EX_CMD(create_flow);
 IB_UVERBS_DECLARE_EX_CMD(destroy_flow);
 IB_UVERBS_DECLARE_EX_CMD(query_device);
 IB_UVERBS_DECLARE_EX_CMD(create_cq);
+IB_UVERBS_DECLARE_EX_CMD(create_qp);
 
 #endif /* UVERBS_H */
index be4cb9f04be3349f433084b1f95cc817f83ad63e..94816aeb95a0a186760fbe98de55edc69266a54c 100644 (file)
@@ -1478,7 +1478,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof(cmd)))
                return -EFAULT;
 
-       INIT_UDATA(&ucore, buf, cmd.response, sizeof(cmd), sizeof(resp));
+       INIT_UDATA(&ucore, buf, (unsigned long)cmd.response, sizeof(cmd), sizeof(resp));
 
        INIT_UDATA(&uhw, buf + sizeof(cmd),
                   (unsigned long)cmd.response + sizeof(resp),
@@ -1741,66 +1741,65 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
        return in_len;
 }
 
-ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
-                           struct ib_device *ib_dev,
-                           const char __user *buf, int in_len,
-                           int out_len)
-{
-       struct ib_uverbs_create_qp      cmd;
-       struct ib_uverbs_create_qp_resp resp;
-       struct ib_udata                 udata;
-       struct ib_uqp_object           *obj;
-       struct ib_device               *device;
-       struct ib_pd                   *pd = NULL;
-       struct ib_xrcd                 *xrcd = NULL;
-       struct ib_uobject              *uninitialized_var(xrcd_uobj);
-       struct ib_cq                   *scq = NULL, *rcq = NULL;
-       struct ib_srq                  *srq = NULL;
-       struct ib_qp                   *qp;
-       struct ib_qp_init_attr          attr;
-       int ret;
-
-       if (out_len < sizeof resp)
-               return -ENOSPC;
-
-       if (copy_from_user(&cmd, buf, sizeof cmd))
-               return -EFAULT;
+static int create_qp(struct ib_uverbs_file *file,
+                    struct ib_udata *ucore,
+                    struct ib_udata *uhw,
+                    struct ib_uverbs_ex_create_qp *cmd,
+                    size_t cmd_sz,
+                    int (*cb)(struct ib_uverbs_file *file,
+                              struct ib_uverbs_ex_create_qp_resp *resp,
+                              struct ib_udata *udata),
+                    void *context)
+{
+       struct ib_uqp_object            *obj;
+       struct ib_device                *device;
+       struct ib_pd                    *pd = NULL;
+       struct ib_xrcd                  *xrcd = NULL;
+       struct ib_uobject               *uninitialized_var(xrcd_uobj);
+       struct ib_cq                    *scq = NULL, *rcq = NULL;
+       struct ib_srq                   *srq = NULL;
+       struct ib_qp                    *qp;
+       char                            *buf;
+       struct ib_qp_init_attr          attr;
+       struct ib_uverbs_ex_create_qp_resp resp;
+       int                             ret;
 
-       if (cmd.qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
+       if (cmd->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
                return -EPERM;
 
-       INIT_UDATA(&udata, buf + sizeof cmd,
-                  (unsigned long) cmd.response + sizeof resp,
-                  in_len - sizeof cmd, out_len - sizeof resp);
-
        obj = kzalloc(sizeof *obj, GFP_KERNEL);
        if (!obj)
                return -ENOMEM;
 
-       init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_class);
+       init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext,
+                 &qp_lock_class);
        down_write(&obj->uevent.uobject.mutex);
 
-       if (cmd.qp_type == IB_QPT_XRC_TGT) {
-               xrcd = idr_read_xrcd(cmd.pd_handle, file->ucontext, &xrcd_uobj);
+       if (cmd->qp_type == IB_QPT_XRC_TGT) {
+               xrcd = idr_read_xrcd(cmd->pd_handle, file->ucontext,
+                                    &xrcd_uobj);
                if (!xrcd) {
                        ret = -EINVAL;
                        goto err_put;
                }
                device = xrcd->device;
        } else {
-               if (cmd.qp_type == IB_QPT_XRC_INI) {
-                       cmd.max_recv_wr = cmd.max_recv_sge = 0;
+               if (cmd->qp_type == IB_QPT_XRC_INI) {
+                       cmd->max_recv_wr = 0;
+                       cmd->max_recv_sge = 0;
                } else {
-                       if (cmd.is_srq) {
-                               srq = idr_read_srq(cmd.srq_handle, file->ucontext);
+                       if (cmd->is_srq) {
+                               srq = idr_read_srq(cmd->srq_handle,
+                                                  file->ucontext);
                                if (!srq || srq->srq_type != IB_SRQT_BASIC) {
                                        ret = -EINVAL;
                                        goto err_put;
                                }
                        }
 
-                       if (cmd.recv_cq_handle != cmd.send_cq_handle) {
-                               rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext, 0);
+                       if (cmd->recv_cq_handle != cmd->send_cq_handle) {
+                               rcq = idr_read_cq(cmd->recv_cq_handle,
+                                                 file->ucontext, 0);
                                if (!rcq) {
                                        ret = -EINVAL;
                                        goto err_put;
@@ -1808,9 +1807,9 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
                        }
                }
 
-               scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, !!rcq);
+               scq = idr_read_cq(cmd->send_cq_handle, file->ucontext, !!rcq);
                rcq = rcq ?: scq;
-               pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
+               pd  = idr_read_pd(cmd->pd_handle, file->ucontext);
                if (!pd || !scq) {
                        ret = -EINVAL;
                        goto err_put;
@@ -1825,31 +1824,49 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        attr.recv_cq       = rcq;
        attr.srq           = srq;
        attr.xrcd          = xrcd;
-       attr.sq_sig_type   = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
-       attr.qp_type       = cmd.qp_type;
+       attr.sq_sig_type   = cmd->sq_sig_all ? IB_SIGNAL_ALL_WR :
+                                             IB_SIGNAL_REQ_WR;
+       attr.qp_type       = cmd->qp_type;
        attr.create_flags  = 0;
 
-       attr.cap.max_send_wr     = cmd.max_send_wr;
-       attr.cap.max_recv_wr     = cmd.max_recv_wr;
-       attr.cap.max_send_sge    = cmd.max_send_sge;
-       attr.cap.max_recv_sge    = cmd.max_recv_sge;
-       attr.cap.max_inline_data = cmd.max_inline_data;
+       attr.cap.max_send_wr     = cmd->max_send_wr;
+       attr.cap.max_recv_wr     = cmd->max_recv_wr;
+       attr.cap.max_send_sge    = cmd->max_send_sge;
+       attr.cap.max_recv_sge    = cmd->max_recv_sge;
+       attr.cap.max_inline_data = cmd->max_inline_data;
 
        obj->uevent.events_reported     = 0;
        INIT_LIST_HEAD(&obj->uevent.event_list);
        INIT_LIST_HEAD(&obj->mcast_list);
 
-       if (cmd.qp_type == IB_QPT_XRC_TGT)
+       if (cmd_sz >= offsetof(typeof(*cmd), create_flags) +
+                     sizeof(cmd->create_flags))
+               attr.create_flags = cmd->create_flags;
+
+       if (attr.create_flags & ~IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
+               ret = -EINVAL;
+               goto err_put;
+       }
+
+       buf = (void *)cmd + sizeof(*cmd);
+       if (cmd_sz > sizeof(*cmd))
+               if (!(buf[0] == 0 && !memcmp(buf, buf + 1,
+                                            cmd_sz - sizeof(*cmd) - 1))) {
+                       ret = -EINVAL;
+                       goto err_put;
+               }
+
+       if (cmd->qp_type == IB_QPT_XRC_TGT)
                qp = ib_create_qp(pd, &attr);
        else
-               qp = device->create_qp(pd, &attr, &udata);
+               qp = device->create_qp(pd, &attr, uhw);
 
        if (IS_ERR(qp)) {
                ret = PTR_ERR(qp);
                goto err_put;
        }
 
-       if (cmd.qp_type != IB_QPT_XRC_TGT) {
+       if (cmd->qp_type != IB_QPT_XRC_TGT) {
                qp->real_qp       = qp;
                qp->device        = device;
                qp->pd            = pd;
@@ -1875,19 +1892,20 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
                goto err_destroy;
 
        memset(&resp, 0, sizeof resp);
-       resp.qpn             = qp->qp_num;
-       resp.qp_handle       = obj->uevent.uobject.id;
-       resp.max_recv_sge    = attr.cap.max_recv_sge;
-       resp.max_send_sge    = attr.cap.max_send_sge;
-       resp.max_recv_wr     = attr.cap.max_recv_wr;
-       resp.max_send_wr     = attr.cap.max_send_wr;
-       resp.max_inline_data = attr.cap.max_inline_data;
+       resp.base.qpn             = qp->qp_num;
+       resp.base.qp_handle       = obj->uevent.uobject.id;
+       resp.base.max_recv_sge    = attr.cap.max_recv_sge;
+       resp.base.max_send_sge    = attr.cap.max_send_sge;
+       resp.base.max_recv_wr     = attr.cap.max_recv_wr;
+       resp.base.max_send_wr     = attr.cap.max_send_wr;
+       resp.base.max_inline_data = attr.cap.max_inline_data;
 
-       if (copy_to_user((void __user *) (unsigned long) cmd.response,
-                        &resp, sizeof resp)) {
-               ret = -EFAULT;
-               goto err_copy;
-       }
+       resp.response_length = offsetof(typeof(resp), response_length) +
+                              sizeof(resp.response_length);
+
+       ret = cb(file, &resp, ucore);
+       if (ret)
+               goto err_cb;
 
        if (xrcd) {
                obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
@@ -1913,9 +1931,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
 
        up_write(&obj->uevent.uobject.mutex);
 
-       return in_len;
-
-err_copy:
+       return 0;
+err_cb:
        idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
 
 err_destroy:
@@ -1937,6 +1954,113 @@ err_put:
        return ret;
 }
 
+static int ib_uverbs_create_qp_cb(struct ib_uverbs_file *file,
+                                 struct ib_uverbs_ex_create_qp_resp *resp,
+                                 struct ib_udata *ucore)
+{
+       if (ib_copy_to_udata(ucore, &resp->base, sizeof(resp->base)))
+               return -EFAULT;
+
+       return 0;
+}
+
+ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
+                           struct ib_device *ib_dev,
+                           const char __user *buf, int in_len,
+                           int out_len)
+{
+       struct ib_uverbs_create_qp      cmd;
+       struct ib_uverbs_ex_create_qp   cmd_ex;
+       struct ib_udata                 ucore;
+       struct ib_udata                 uhw;
+       ssize_t resp_size = sizeof(struct ib_uverbs_create_qp_resp);
+       int                             err;
+
+       if (out_len < resp_size)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof(cmd)))
+               return -EFAULT;
+
+       INIT_UDATA(&ucore, buf, (unsigned long)cmd.response, sizeof(cmd),
+                  resp_size);
+       INIT_UDATA(&uhw, buf + sizeof(cmd),
+                  (unsigned long)cmd.response + resp_size,
+                  in_len - sizeof(cmd), out_len - resp_size);
+
+       memset(&cmd_ex, 0, sizeof(cmd_ex));
+       cmd_ex.user_handle = cmd.user_handle;
+       cmd_ex.pd_handle = cmd.pd_handle;
+       cmd_ex.send_cq_handle = cmd.send_cq_handle;
+       cmd_ex.recv_cq_handle = cmd.recv_cq_handle;
+       cmd_ex.srq_handle = cmd.srq_handle;
+       cmd_ex.max_send_wr = cmd.max_send_wr;
+       cmd_ex.max_recv_wr = cmd.max_recv_wr;
+       cmd_ex.max_send_sge = cmd.max_send_sge;
+       cmd_ex.max_recv_sge = cmd.max_recv_sge;
+       cmd_ex.max_inline_data = cmd.max_inline_data;
+       cmd_ex.sq_sig_all = cmd.sq_sig_all;
+       cmd_ex.qp_type = cmd.qp_type;
+       cmd_ex.is_srq = cmd.is_srq;
+
+       err = create_qp(file, &ucore, &uhw, &cmd_ex,
+                       offsetof(typeof(cmd_ex), is_srq) +
+                       sizeof(cmd.is_srq), ib_uverbs_create_qp_cb,
+                       NULL);
+
+       if (err)
+               return err;
+
+       return in_len;
+}
+
+static int ib_uverbs_ex_create_qp_cb(struct ib_uverbs_file *file,
+                                    struct ib_uverbs_ex_create_qp_resp *resp,
+                                    struct ib_udata *ucore)
+{
+       if (ib_copy_to_udata(ucore, resp, resp->response_length))
+               return -EFAULT;
+
+       return 0;
+}
+
+int ib_uverbs_ex_create_qp(struct ib_uverbs_file *file,
+                          struct ib_device *ib_dev,
+                          struct ib_udata *ucore,
+                          struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_create_qp_resp resp;
+       struct ib_uverbs_ex_create_qp cmd = {0};
+       int err;
+
+       if (ucore->inlen < (offsetof(typeof(cmd), comp_mask) +
+                           sizeof(cmd.comp_mask)))
+               return -EINVAL;
+
+       err = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
+       if (err)
+               return err;
+
+       if (cmd.comp_mask)
+               return -EINVAL;
+
+       if (cmd.reserved)
+               return -EINVAL;
+
+       if (ucore->outlen < (offsetof(typeof(resp), response_length) +
+                            sizeof(resp.response_length)))
+               return -ENOSPC;
+
+       err = create_qp(file, ucore, uhw, &cmd,
+                       min(ucore->inlen, sizeof(cmd)),
+                       ib_uverbs_ex_create_qp_cb, NULL);
+
+       if (err)
+               return err;
+
+       return 0;
+}
+
 ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file,
                          struct ib_device *ib_dev,
                          const char __user *buf, int in_len, int out_len)
@@ -2221,7 +2345,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        attr->alt_ah_attr.port_num          = cmd.alt_dest.port_num;
 
        if (qp->real_qp == qp) {
-               ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask);
+               ret = ib_resolve_eth_dmac(qp, attr, &cmd.attr_mask);
                if (ret)
                        goto release_qp;
                ret = qp->device->modify_qp(qp, attr,
@@ -2303,6 +2427,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
        return in_len;
 }
 
+static void *alloc_wr(size_t wr_size, __u32 num_sge)
+{
+       return kmalloc(ALIGN(wr_size, sizeof (struct ib_sge)) +
+                        num_sge * sizeof (struct ib_sge), GFP_KERNEL);
+};
+
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                            struct ib_device *ib_dev,
                            const char __user *buf, int in_len,
@@ -2351,14 +2481,83 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                        goto out_put;
                }
 
-               next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
-                              user_wr->num_sge * sizeof (struct ib_sge),
-                              GFP_KERNEL);
-               if (!next) {
-                       ret = -ENOMEM;
+               if (is_ud) {
+                       struct ib_ud_wr *ud;
+
+                       if (user_wr->opcode != IB_WR_SEND &&
+                           user_wr->opcode != IB_WR_SEND_WITH_IMM) {
+                               ret = -EINVAL;
+                               goto out_put;
+                       }
+
+                       ud = alloc_wr(sizeof(*ud), user_wr->num_sge);
+                       if (!ud) {
+                               ret = -ENOMEM;
+                               goto out_put;
+                       }
+
+                       ud->ah = idr_read_ah(user_wr->wr.ud.ah, file->ucontext);
+                       if (!ud->ah) {
+                               kfree(ud);
+                               ret = -EINVAL;
+                               goto out_put;
+                       }
+                       ud->remote_qpn = user_wr->wr.ud.remote_qpn;
+                       ud->remote_qkey = user_wr->wr.ud.remote_qkey;
+
+                       next = &ud->wr;
+               } else if (user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                          user_wr->opcode == IB_WR_RDMA_WRITE ||
+                          user_wr->opcode == IB_WR_RDMA_READ) {
+                       struct ib_rdma_wr *rdma;
+
+                       rdma = alloc_wr(sizeof(*rdma), user_wr->num_sge);
+                       if (!rdma) {
+                               ret = -ENOMEM;
+                               goto out_put;
+                       }
+
+                       rdma->remote_addr = user_wr->wr.rdma.remote_addr;
+                       rdma->rkey = user_wr->wr.rdma.rkey;
+
+                       next = &rdma->wr;
+               } else if (user_wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                          user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
+                       struct ib_atomic_wr *atomic;
+
+                       atomic = alloc_wr(sizeof(*atomic), user_wr->num_sge);
+                       if (!atomic) {
+                               ret = -ENOMEM;
+                               goto out_put;
+                       }
+
+                       atomic->remote_addr = user_wr->wr.atomic.remote_addr;
+                       atomic->compare_add = user_wr->wr.atomic.compare_add;
+                       atomic->swap = user_wr->wr.atomic.swap;
+                       atomic->rkey = user_wr->wr.atomic.rkey;
+
+                       next = &atomic->wr;
+               } else if (user_wr->opcode == IB_WR_SEND ||
+                          user_wr->opcode == IB_WR_SEND_WITH_IMM ||
+                          user_wr->opcode == IB_WR_SEND_WITH_INV) {
+                       next = alloc_wr(sizeof(*next), user_wr->num_sge);
+                       if (!next) {
+                               ret = -ENOMEM;
+                               goto out_put;
+                       }
+               } else {
+                       ret = -EINVAL;
                        goto out_put;
                }
 
+               if (user_wr->opcode == IB_WR_SEND_WITH_IMM ||
+                   user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+                       next->ex.imm_data =
+                                       (__be32 __force) user_wr->ex.imm_data;
+               } else if (user_wr->opcode == IB_WR_SEND_WITH_INV) {
+                       next->ex.invalidate_rkey = user_wr->ex.invalidate_rkey;
+               }
+
                if (!last)
                        wr = next;
                else
@@ -2371,60 +2570,6 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                next->opcode     = user_wr->opcode;
                next->send_flags = user_wr->send_flags;
 
-               if (is_ud) {
-                       if (next->opcode != IB_WR_SEND &&
-                           next->opcode != IB_WR_SEND_WITH_IMM) {
-                               ret = -EINVAL;
-                               goto out_put;
-                       }
-
-                       next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah,
-                                                    file->ucontext);
-                       if (!next->wr.ud.ah) {
-                               ret = -EINVAL;
-                               goto out_put;
-                       }
-                       next->wr.ud.remote_qpn  = user_wr->wr.ud.remote_qpn;
-                       next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey;
-                       if (next->opcode == IB_WR_SEND_WITH_IMM)
-                               next->ex.imm_data =
-                                       (__be32 __force) user_wr->ex.imm_data;
-               } else {
-                       switch (next->opcode) {
-                       case IB_WR_RDMA_WRITE_WITH_IMM:
-                               next->ex.imm_data =
-                                       (__be32 __force) user_wr->ex.imm_data;
-                       case IB_WR_RDMA_WRITE:
-                       case IB_WR_RDMA_READ:
-                               next->wr.rdma.remote_addr =
-                                       user_wr->wr.rdma.remote_addr;
-                               next->wr.rdma.rkey        =
-                                       user_wr->wr.rdma.rkey;
-                               break;
-                       case IB_WR_SEND_WITH_IMM:
-                               next->ex.imm_data =
-                                       (__be32 __force) user_wr->ex.imm_data;
-                               break;
-                       case IB_WR_SEND_WITH_INV:
-                               next->ex.invalidate_rkey =
-                                       user_wr->ex.invalidate_rkey;
-                               break;
-                       case IB_WR_ATOMIC_CMP_AND_SWP:
-                       case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               next->wr.atomic.remote_addr =
-                                       user_wr->wr.atomic.remote_addr;
-                               next->wr.atomic.compare_add =
-                                       user_wr->wr.atomic.compare_add;
-                               next->wr.atomic.swap = user_wr->wr.atomic.swap;
-                               next->wr.atomic.rkey = user_wr->wr.atomic.rkey;
-                       case IB_WR_SEND:
-                               break;
-                       default:
-                               ret = -EINVAL;
-                               goto out_put;
-                       }
-               }
-
                if (next->num_sge) {
                        next->sg_list = (void *) next +
                                ALIGN(sizeof *next, sizeof (struct ib_sge));
@@ -2458,8 +2603,8 @@ out_put:
        put_qp_read(qp);
 
        while (wr) {
-               if (is_ud && wr->wr.ud.ah)
-                       put_ah_read(wr->wr.ud.ah);
+               if (is_ud && ud_wr(wr)->ah)
+                       put_ah_read(ud_wr(wr)->ah);
                next = wr->next;
                kfree(wr);
                wr = next;
@@ -2698,7 +2843,6 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        attr.grh.sgid_index    = cmd.attr.grh.sgid_index;
        attr.grh.hop_limit     = cmd.attr.grh.hop_limit;
        attr.grh.traffic_class = cmd.attr.grh.traffic_class;
-       attr.vlan_id           = 0;
        memset(&attr.dmac, 0, sizeof(attr.dmac));
        memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16);
 
index c29a660c72fe3674cea593f9cdab483f133edd8f..e3ef28861be63dd453d0fd1b55ec21f939919624 100644 (file)
@@ -127,6 +127,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_EX_CMD_DESTROY_FLOW]     = ib_uverbs_ex_destroy_flow,
        [IB_USER_VERBS_EX_CMD_QUERY_DEVICE]     = ib_uverbs_ex_query_device,
        [IB_USER_VERBS_EX_CMD_CREATE_CQ]        = ib_uverbs_ex_create_cq,
+       [IB_USER_VERBS_EX_CMD_CREATE_QP]        = ib_uverbs_ex_create_qp,
 };
 
 static void ib_uverbs_add_one(struct ib_device *device);
index abd97247443e437ffff62e8238610657ca355394..7d2f14c9bbefaf1f3c28eac11b7bcefbc2802927 100644 (file)
@@ -141,8 +141,8 @@ void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst,
        dst->preference         = src->preference;
        dst->packet_life_time_selector = src->packet_life_time_selector;
 
-       memset(dst->smac, 0, sizeof(dst->smac));
        memset(dst->dmac, 0, sizeof(dst->dmac));
-       dst->vlan_id = 0xffff;
+       dst->net = NULL;
+       dst->ifindex = 0;
 }
 EXPORT_SYMBOL(ib_copy_path_rec_from_user);
index e1f2c9887f3f48ebc20c0931304ae75c5f65c03f..043a60ee6836db72e498410ebd80e004ed220c7d 100644 (file)
@@ -41,6 +41,9 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/addrconf.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_cache.h>
@@ -70,7 +73,7 @@ static const char * const ib_events[] = {
        [IB_EVENT_GID_CHANGE]           = "GID changed",
 };
 
-const char *ib_event_msg(enum ib_event_type event)
+const char *__attribute_const__ ib_event_msg(enum ib_event_type event)
 {
        size_t index = event;
 
@@ -104,7 +107,7 @@ static const char * const wc_statuses[] = {
        [IB_WC_GENERAL_ERR]             = "general error",
 };
 
-const char *ib_wc_status_msg(enum ib_wc_status status)
+const char *__attribute_const__ ib_wc_status_msg(enum ib_wc_status status)
 {
        size_t index = status;
 
@@ -308,6 +311,35 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
 }
 EXPORT_SYMBOL(ib_create_ah);
 
+struct find_gid_index_context {
+       u16 vlan_id;
+};
+
+static bool find_gid_index(const union ib_gid *gid,
+                          const struct ib_gid_attr *gid_attr,
+                          void *context)
+{
+       struct find_gid_index_context *ctx =
+               (struct find_gid_index_context *)context;
+
+       if ((!!(ctx->vlan_id != 0xffff) == !is_vlan_dev(gid_attr->ndev)) ||
+           (is_vlan_dev(gid_attr->ndev) &&
+            vlan_dev_vlan_id(gid_attr->ndev) != ctx->vlan_id))
+               return false;
+
+       return true;
+}
+
+static int get_sgid_index_from_eth(struct ib_device *device, u8 port_num,
+                                  u16 vlan_id, const union ib_gid *sgid,
+                                  u16 *gid_index)
+{
+       struct find_gid_index_context context = {.vlan_id = vlan_id};
+
+       return ib_find_gid_by_filter(device, sgid, port_num, find_gid_index,
+                                    &context, gid_index);
+}
+
 int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                       const struct ib_wc *wc, const struct ib_grh *grh,
                       struct ib_ah_attr *ah_attr)
@@ -318,21 +350,30 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
 
        memset(ah_attr, 0, sizeof *ah_attr);
        if (rdma_cap_eth_ah(device, port_num)) {
+               u16 vlan_id = wc->wc_flags & IB_WC_WITH_VLAN ?
+                               wc->vlan_id : 0xffff;
+
                if (!(wc->wc_flags & IB_WC_GRH))
                        return -EPROTOTYPE;
 
-               if (wc->wc_flags & IB_WC_WITH_SMAC &&
-                   wc->wc_flags & IB_WC_WITH_VLAN) {
-                       memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
-                       ah_attr->vlan_id = wc->vlan_id;
-               } else {
+               if (!(wc->wc_flags & IB_WC_WITH_SMAC) ||
+                   !(wc->wc_flags & IB_WC_WITH_VLAN)) {
                        ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
-                                       ah_attr->dmac, &ah_attr->vlan_id);
+                                                        ah_attr->dmac,
+                                                        wc->wc_flags & IB_WC_WITH_VLAN ?
+                                                        NULL : &vlan_id,
+                                                        0);
                        if (ret)
                                return ret;
                }
-       } else {
-               ah_attr->vlan_id = 0xffff;
+
+               ret = get_sgid_index_from_eth(device, port_num, vlan_id,
+                                             &grh->dgid, &gid_index);
+               if (ret)
+                       return ret;
+
+               if (wc->wc_flags & IB_WC_WITH_SMAC)
+                       memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
        }
 
        ah_attr->dlid = wc->slid;
@@ -344,10 +385,13 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                ah_attr->ah_flags = IB_AH_GRH;
                ah_attr->grh.dgid = grh->sgid;
 
-               ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
-                                        &gid_index);
-               if (ret)
-                       return ret;
+               if (!rdma_cap_eth_ah(device, port_num)) {
+                       ret = ib_find_cached_gid_by_port(device, &grh->dgid,
+                                                        port_num, NULL,
+                                                        &gid_index);
+                       if (ret)
+                               return ret;
+               }
 
                ah_attr->grh.sgid_index = (u8) gid_index;
                flow_class = be32_to_cpu(grh->version_tclass_flow);
@@ -617,9 +661,7 @@ EXPORT_SYMBOL(ib_create_qp);
 static const struct {
        int                     valid;
        enum ib_qp_attr_mask    req_param[IB_QPT_MAX];
-       enum ib_qp_attr_mask    req_param_add_eth[IB_QPT_MAX];
        enum ib_qp_attr_mask    opt_param[IB_QPT_MAX];
-       enum ib_qp_attr_mask    opt_param_add_eth[IB_QPT_MAX];
 } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
        [IB_QPS_RESET] = {
                [IB_QPS_RESET] = { .valid = 1 },
@@ -700,12 +742,6 @@ static const struct {
                                                IB_QP_MAX_DEST_RD_ATOMIC        |
                                                IB_QP_MIN_RNR_TIMER),
                        },
-                       .req_param_add_eth = {
-                               [IB_QPT_RC]  = (IB_QP_SMAC),
-                               [IB_QPT_UC]  = (IB_QP_SMAC),
-                               [IB_QPT_XRC_INI]  = (IB_QP_SMAC),
-                               [IB_QPT_XRC_TGT]  = (IB_QP_SMAC)
-                       },
                        .opt_param = {
                                 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX               |
                                                 IB_QP_QKEY),
@@ -726,21 +762,7 @@ static const struct {
                                 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX               |
                                                 IB_QP_QKEY),
                         },
-                       .opt_param_add_eth = {
-                               [IB_QPT_RC]  = (IB_QP_ALT_SMAC                  |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_UC]  = (IB_QP_ALT_SMAC                  |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_XRC_INI]  = (IB_QP_ALT_SMAC                     |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_XRC_TGT]  = (IB_QP_ALT_SMAC                     |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID)
-                       }
-               }
+               },
        },
        [IB_QPS_RTR]   = {
                [IB_QPS_RESET] = { .valid = 1 },
@@ -962,13 +984,6 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
        req_param = qp_state_table[cur_state][next_state].req_param[type];
        opt_param = qp_state_table[cur_state][next_state].opt_param[type];
 
-       if (ll == IB_LINK_LAYER_ETHERNET) {
-               req_param |= qp_state_table[cur_state][next_state].
-                       req_param_add_eth[type];
-               opt_param |= qp_state_table[cur_state][next_state].
-                       opt_param_add_eth[type];
-       }
-
        if ((mask & req_param) != req_param)
                return 0;
 
@@ -979,40 +994,52 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
 }
 EXPORT_SYMBOL(ib_modify_qp_is_ok);
 
-int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
-                           struct ib_qp_attr *qp_attr, int *qp_attr_mask)
+int ib_resolve_eth_dmac(struct ib_qp *qp,
+                       struct ib_qp_attr *qp_attr, int *qp_attr_mask)
 {
        int           ret = 0;
-       union ib_gid  sgid;
 
-       if ((*qp_attr_mask & IB_QP_AV)  &&
-           (rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))) {
-               ret = ib_query_gid(qp->device, qp_attr->ah_attr.port_num,
-                                  qp_attr->ah_attr.grh.sgid_index, &sgid);
-               if (ret)
-                       goto out;
+       if (*qp_attr_mask & IB_QP_AV) {
+               if (qp_attr->ah_attr.port_num < rdma_start_port(qp->device) ||
+                   qp_attr->ah_attr.port_num > rdma_end_port(qp->device))
+                       return -EINVAL;
+
+               if (!rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))
+                       return 0;
+
                if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) {
-                       rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, qp_attr->ah_attr.dmac);
-                       rdma_get_ll_mac((struct in6_addr *)sgid.raw, qp_attr->smac);
-                       if (!(*qp_attr_mask & IB_QP_VID))
-                               qp_attr->vlan_id = rdma_get_vlan_id(&sgid);
+                       rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw,
+                                       qp_attr->ah_attr.dmac);
                } else {
-                       ret = rdma_addr_find_dmac_by_grh(&sgid, &qp_attr->ah_attr.grh.dgid,
-                                       qp_attr->ah_attr.dmac, &qp_attr->vlan_id);
-                       if (ret)
-                               goto out;
-                       ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr->smac, NULL);
-                       if (ret)
+                       union ib_gid            sgid;
+                       struct ib_gid_attr      sgid_attr;
+                       int                     ifindex;
+
+                       ret = ib_query_gid(qp->device,
+                                          qp_attr->ah_attr.port_num,
+                                          qp_attr->ah_attr.grh.sgid_index,
+                                          &sgid, &sgid_attr);
+
+                       if (ret || !sgid_attr.ndev) {
+                               if (!ret)
+                                       ret = -ENXIO;
                                goto out;
+                       }
+
+                       ifindex = sgid_attr.ndev->ifindex;
+
+                       ret = rdma_addr_find_dmac_by_grh(&sgid,
+                                                        &qp_attr->ah_attr.grh.dgid,
+                                                        qp_attr->ah_attr.dmac,
+                                                        NULL, ifindex);
+
+                       dev_put(sgid_attr.ndev);
                }
-               *qp_attr_mask |= IB_QP_SMAC;
-               if (qp_attr->vlan_id < 0xFFFF)
-                       *qp_attr_mask |= IB_QP_VID;
        }
 out:
        return ret;
 }
-EXPORT_SYMBOL(ib_resolve_eth_l2_attrs);
+EXPORT_SYMBOL(ib_resolve_eth_dmac);
 
 
 int ib_modify_qp(struct ib_qp *qp,
@@ -1021,7 +1048,7 @@ int ib_modify_qp(struct ib_qp *qp,
 {
        int ret;
 
-       ret = ib_resolve_eth_l2_attrs(qp, qp_attr, &qp_attr_mask);
+       ret = ib_resolve_eth_dmac(qp, qp_attr, &qp_attr_mask);
        if (ret)
                return ret;
 
@@ -1253,31 +1280,6 @@ struct ib_mr *ib_alloc_mr(struct ib_pd *pd,
 }
 EXPORT_SYMBOL(ib_alloc_mr);
 
-struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
-                                                         int max_page_list_len)
-{
-       struct ib_fast_reg_page_list *page_list;
-
-       if (!device->alloc_fast_reg_page_list)
-               return ERR_PTR(-ENOSYS);
-
-       page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
-
-       if (!IS_ERR(page_list)) {
-               page_list->device = device;
-               page_list->max_page_list_len = max_page_list_len;
-       }
-
-       return page_list;
-}
-EXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
-
-void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
-{
-       page_list->device->free_fast_reg_page_list(page_list);
-}
-EXPORT_SYMBOL(ib_free_fast_reg_page_list);
-
 /* Memory windows */
 
 struct ib_mw *ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
@@ -1469,3 +1471,110 @@ int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
                mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS;
 }
 EXPORT_SYMBOL(ib_check_mr_status);
+
+/**
+ * ib_map_mr_sg() - Map the largest prefix of a dma mapped SG list
+ *     and set it the memory region.
+ * @mr:            memory region
+ * @sg:            dma mapped scatterlist
+ * @sg_nents:      number of entries in sg
+ * @page_size:     page vector desired page size
+ *
+ * Constraints:
+ * - The first sg element is allowed to have an offset.
+ * - Each sg element must be aligned to page_size (or physically
+ *   contiguous to the previous element). In case an sg element has a
+ *   non contiguous offset, the mapping prefix will not include it.
+ * - The last sg element is allowed to have length less than page_size.
+ * - If sg_nents total byte length exceeds the mr max_num_sge * page_size
+ *   then only max_num_sg entries will be mapped.
+ *
+ * Returns the number of sg elements that were mapped to the memory region.
+ *
+ * After this completes successfully, the  memory region
+ * is ready for registration.
+ */
+int ib_map_mr_sg(struct ib_mr *mr,
+                struct scatterlist *sg,
+                int sg_nents,
+                unsigned int page_size)
+{
+       if (unlikely(!mr->device->map_mr_sg))
+               return -ENOSYS;
+
+       mr->page_size = page_size;
+
+       return mr->device->map_mr_sg(mr, sg, sg_nents);
+}
+EXPORT_SYMBOL(ib_map_mr_sg);
+
+/**
+ * ib_sg_to_pages() - Convert the largest prefix of a sg list
+ *     to a page vector
+ * @mr:            memory region
+ * @sgl:           dma mapped scatterlist
+ * @sg_nents:      number of entries in sg
+ * @set_page:      driver page assignment function pointer
+ *
+ * Core service helper for drivers to covert the largest
+ * prefix of given sg list to a page vector. The sg list
+ * prefix converted is the prefix that meet the requirements
+ * of ib_map_mr_sg.
+ *
+ * Returns the number of sg elements that were assigned to
+ * a page vector.
+ */
+int ib_sg_to_pages(struct ib_mr *mr,
+                  struct scatterlist *sgl,
+                  int sg_nents,
+                  int (*set_page)(struct ib_mr *, u64))
+{
+       struct scatterlist *sg;
+       u64 last_end_dma_addr = 0, last_page_addr = 0;
+       unsigned int last_page_off = 0;
+       u64 page_mask = ~((u64)mr->page_size - 1);
+       int i;
+
+       mr->iova = sg_dma_address(&sgl[0]);
+       mr->length = 0;
+
+       for_each_sg(sgl, sg, sg_nents, i) {
+               u64 dma_addr = sg_dma_address(sg);
+               unsigned int dma_len = sg_dma_len(sg);
+               u64 end_dma_addr = dma_addr + dma_len;
+               u64 page_addr = dma_addr & page_mask;
+
+               if (i && page_addr != dma_addr) {
+                       if (last_end_dma_addr != dma_addr) {
+                               /* gap */
+                               goto done;
+
+                       } else if (last_page_off + dma_len <= mr->page_size) {
+                               /* chunk this fragment with the last */
+                               mr->length += dma_len;
+                               last_end_dma_addr += dma_len;
+                               last_page_off += dma_len;
+                               continue;
+                       } else {
+                               /* map starting from the next page */
+                               page_addr = last_page_addr + mr->page_size;
+                               dma_len -= mr->page_size - last_page_off;
+                       }
+               }
+
+               do {
+                       if (unlikely(set_page(mr, page_addr)))
+                               goto done;
+                       page_addr += mr->page_size;
+               } while (page_addr < end_dma_addr);
+
+               mr->length += dma_len;
+               last_end_dma_addr = end_dma_addr;
+               last_page_addr = end_dma_addr & page_mask;
+               last_page_off = end_dma_addr & ~page_mask;
+       }
+
+done:
+       return i;
+}
+EXPORT_SYMBOL(ib_sg_to_pages);
index cf5474ae68ff010ae23004c45d4b421a1ff1b49c..cfe404925a399f2be0cd1bdbc23c262ad1b24ca9 100644 (file)
@@ -123,7 +123,7 @@ static int iwch_poll_cq_one(struct iwch_dev *rhp, struct iwch_cq *chp,
                        wc->opcode = IB_WC_LOCAL_INV;
                        break;
                case T3_FAST_REGISTER:
-                       wc->opcode = IB_WC_FAST_REG_MR;
+                       wc->opcode = IB_WC_REG_MR;
                        break;
                default:
                        printk(KERN_ERR MOD "Unexpected opcode %d "
index 93308c45f298d921fb3fd25b195a2b5970471fe5..c34725ca0bb426606e16708fafab2995490d7187 100644 (file)
@@ -463,6 +463,7 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr)
                return -EINVAL;
 
        mhp = to_iwch_mr(ib_mr);
+       kfree(mhp->pages);
        rhp = mhp->rhp;
        mmid = mhp->attr.stag >> 8;
        cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
@@ -821,6 +822,12 @@ static struct ib_mr *iwch_alloc_mr(struct ib_pd *pd,
        if (!mhp)
                goto err;
 
+       mhp->pages = kcalloc(max_num_sg, sizeof(u64), GFP_KERNEL);
+       if (!mhp->pages) {
+               ret = -ENOMEM;
+               goto pl_err;
+       }
+
        mhp->rhp = rhp;
        ret = iwch_alloc_pbl(mhp, max_num_sg);
        if (ret)
@@ -847,31 +854,34 @@ err3:
 err2:
        iwch_free_pbl(mhp);
 err1:
+       kfree(mhp->pages);
+pl_err:
        kfree(mhp);
 err:
        return ERR_PTR(ret);
 }
 
-static struct ib_fast_reg_page_list *iwch_alloc_fastreg_pbl(
-                                       struct ib_device *device,
-                                       int page_list_len)
+static int iwch_set_page(struct ib_mr *ibmr, u64 addr)
 {
-       struct ib_fast_reg_page_list *page_list;
+       struct iwch_mr *mhp = to_iwch_mr(ibmr);
 
-       page_list = kmalloc(sizeof *page_list + page_list_len * sizeof(u64),
-                           GFP_KERNEL);
-       if (!page_list)
-               return ERR_PTR(-ENOMEM);
+       if (unlikely(mhp->npages == mhp->attr.pbl_size))
+               return -ENOMEM;
 
-       page_list->page_list = (u64 *)(page_list + 1);
-       page_list->max_page_list_len = page_list_len;
+       mhp->pages[mhp->npages++] = addr;
 
-       return page_list;
+       return 0;
 }
 
-static void iwch_free_fastreg_pbl(struct ib_fast_reg_page_list *page_list)
+static int iwch_map_mr_sg(struct ib_mr *ibmr,
+                         struct scatterlist *sg,
+                         int sg_nents)
 {
-       kfree(page_list);
+       struct iwch_mr *mhp = to_iwch_mr(ibmr);
+
+       mhp->npages = 0;
+
+       return ib_sg_to_pages(ibmr, sg, sg_nents, iwch_set_page);
 }
 
 static int iwch_destroy_qp(struct ib_qp *ib_qp)
@@ -1450,8 +1460,7 @@ int iwch_register_device(struct iwch_dev *dev)
        dev->ibdev.bind_mw = iwch_bind_mw;
        dev->ibdev.dealloc_mw = iwch_dealloc_mw;
        dev->ibdev.alloc_mr = iwch_alloc_mr;
-       dev->ibdev.alloc_fast_reg_page_list = iwch_alloc_fastreg_pbl;
-       dev->ibdev.free_fast_reg_page_list = iwch_free_fastreg_pbl;
+       dev->ibdev.map_mr_sg = iwch_map_mr_sg;
        dev->ibdev.attach_mcast = iwch_multicast_attach;
        dev->ibdev.detach_mcast = iwch_multicast_detach;
        dev->ibdev.process_mad = iwch_process_mad;
index 87c14b0c5ac0c9514d9df59ddd39da08cfef8342..2ac85b86a680dea89becaf76c75956cda42a1644 100644 (file)
@@ -77,6 +77,8 @@ struct iwch_mr {
        struct iwch_dev *rhp;
        u64 kva;
        struct tpt_attributes attr;
+       u64 *pages;
+       u32 npages;
 };
 
 typedef struct iwch_mw iwch_mw_handle;
index b57c0befd962b837f45b36719663a945caf3cdbe..d0548fc6395eac2343775ea4a4b85d3c83bb98b0 100644 (file)
@@ -95,8 +95,8 @@ static int build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
        wqe->write.reserved[0] = 0;
        wqe->write.reserved[1] = 0;
        wqe->write.reserved[2] = 0;
-       wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);
-       wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);
+       wqe->write.stag_sink = cpu_to_be32(rdma_wr(wr)->rkey);
+       wqe->write.to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr);
 
        if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
                plen = 4;
@@ -137,8 +137,8 @@ static int build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
                wqe->read.local_inv = 0;
        wqe->read.reserved[0] = 0;
        wqe->read.reserved[1] = 0;
-       wqe->read.rem_stag = cpu_to_be32(wr->wr.rdma.rkey);
-       wqe->read.rem_to = cpu_to_be64(wr->wr.rdma.remote_addr);
+       wqe->read.rem_stag = cpu_to_be32(rdma_wr(wr)->rkey);
+       wqe->read.rem_to = cpu_to_be64(rdma_wr(wr)->remote_addr);
        wqe->read.local_stag = cpu_to_be32(wr->sg_list[0].lkey);
        wqe->read.local_len = cpu_to_be32(wr->sg_list[0].length);
        wqe->read.local_to = cpu_to_be64(wr->sg_list[0].addr);
@@ -146,27 +146,28 @@ static int build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
        return 0;
 }
 
-static int build_fastreg(union t3_wr *wqe, struct ib_send_wr *wr,
-                               u8 *flit_cnt, int *wr_cnt, struct t3_wq *wq)
+static int build_memreg(union t3_wr *wqe, struct ib_reg_wr *wr,
+                         u8 *flit_cnt, int *wr_cnt, struct t3_wq *wq)
 {
+       struct iwch_mr *mhp = to_iwch_mr(wr->mr);
        int i;
        __be64 *p;
 
-       if (wr->wr.fast_reg.page_list_len > T3_MAX_FASTREG_DEPTH)
+       if (mhp->npages > T3_MAX_FASTREG_DEPTH)
                return -EINVAL;
        *wr_cnt = 1;
-       wqe->fastreg.stag = cpu_to_be32(wr->wr.fast_reg.rkey);
-       wqe->fastreg.len = cpu_to_be32(wr->wr.fast_reg.length);
-       wqe->fastreg.va_base_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
+       wqe->fastreg.stag = cpu_to_be32(wr->key);
+       wqe->fastreg.len = cpu_to_be32(mhp->ibmr.length);
+       wqe->fastreg.va_base_hi = cpu_to_be32(mhp->ibmr.iova >> 32);
        wqe->fastreg.va_base_lo_fbo =
-                               cpu_to_be32(wr->wr.fast_reg.iova_start & 0xffffffff);
+                               cpu_to_be32(mhp->ibmr.iova & 0xffffffff);
        wqe->fastreg.page_type_perms = cpu_to_be32(
-               V_FR_PAGE_COUNT(wr->wr.fast_reg.page_list_len) |
-               V_FR_PAGE_SIZE(wr->wr.fast_reg.page_shift-12) |
+               V_FR_PAGE_COUNT(mhp->npages) |
+               V_FR_PAGE_SIZE(ilog2(wr->mr->page_size) - 12) |
                V_FR_TYPE(TPT_VATO) |
-               V_FR_PERMS(iwch_ib_to_tpt_access(wr->wr.fast_reg.access_flags)));
+               V_FR_PERMS(iwch_ib_to_tpt_access(wr->access)));
        p = &wqe->fastreg.pbl_addrs[0];
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++) {
+       for (i = 0; i < mhp->npages; i++, p++) {
 
                /* If we need a 2nd WR, then set it up */
                if (i == T3_MAX_FASTREG_FRAG) {
@@ -175,14 +176,14 @@ static int build_fastreg(union t3_wr *wqe, struct ib_send_wr *wr,
                                Q_PTR2IDX((wq->wptr+1), wq->size_log2));
                        build_fw_riwrh((void *)wqe, T3_WR_FASTREG, 0,
                               Q_GENBIT(wq->wptr + 1, wq->size_log2),
-                              0, 1 + wr->wr.fast_reg.page_list_len - T3_MAX_FASTREG_FRAG,
+                              0, 1 + mhp->npages - T3_MAX_FASTREG_FRAG,
                               T3_EOP);
 
                        p = &wqe->pbl_frag.pbl_addrs[0];
                }
-               *p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);
+               *p = cpu_to_be64((u64)mhp->pages[i]);
        }
-       *flit_cnt = 5 + wr->wr.fast_reg.page_list_len;
+       *flit_cnt = 5 + mhp->npages;
        if (*flit_cnt > 15)
                *flit_cnt = 15;
        return 0;
@@ -414,10 +415,10 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        if (!qhp->wq.oldest_read)
                                qhp->wq.oldest_read = sqp;
                        break;
-               case IB_WR_FAST_REG_MR:
+               case IB_WR_REG_MR:
                        t3_wr_opcode = T3_WR_FASTREG;
-                       err = build_fastreg(wqe, wr, &t3_wr_flit_cnt,
-                                                &wr_cnt, &qhp->wq);
+                       err = build_memreg(wqe, reg_wr(wr), &t3_wr_flit_cnt,
+                                          &wr_cnt, &qhp->wq);
                        break;
                case IB_WR_LOCAL_INV:
                        if (wr->send_flags & IB_SEND_FENCE)
index debc39d2cbc2a61d66901dd20ef531703717ed29..c9cffced00ca1df11683b961d0cc48f983056a07 100644 (file)
@@ -632,22 +632,18 @@ static void best_mtu(const unsigned short *mtus, unsigned short mtu,
 
 static int send_connect(struct c4iw_ep *ep)
 {
-       struct cpl_act_open_req *req;
-       struct cpl_t5_act_open_req *t5_req;
-       struct cpl_act_open_req6 *req6;
-       struct cpl_t5_act_open_req6 *t5_req6;
+       struct cpl_act_open_req *req = NULL;
+       struct cpl_t5_act_open_req *t5req = NULL;
+       struct cpl_t6_act_open_req *t6req = NULL;
+       struct cpl_act_open_req6 *req6 = NULL;
+       struct cpl_t5_act_open_req6 *t5req6 = NULL;
+       struct cpl_t6_act_open_req6 *t6req6 = NULL;
        struct sk_buff *skb;
        u64 opt0;
        u32 opt2;
        unsigned int mtu_idx;
        int wscale;
-       int wrlen;
-       int sizev4 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
-                               sizeof(struct cpl_act_open_req) :
-                               sizeof(struct cpl_t5_act_open_req);
-       int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
-                               sizeof(struct cpl_act_open_req6) :
-                               sizeof(struct cpl_t5_act_open_req6);
+       int win, sizev4, sizev6, wrlen;
        struct sockaddr_in *la = (struct sockaddr_in *)
                                 &ep->com.mapped_local_addr;
        struct sockaddr_in *ra = (struct sockaddr_in *)
@@ -656,8 +652,28 @@ static int send_connect(struct c4iw_ep *ep)
                                   &ep->com.mapped_local_addr;
        struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
                                   &ep->com.mapped_remote_addr;
-       int win;
        int ret;
+       enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
+       u32 isn = (prandom_u32() & ~7UL) - 1;
+
+       switch (CHELSIO_CHIP_VERSION(adapter_type)) {
+       case CHELSIO_T4:
+               sizev4 = sizeof(struct cpl_act_open_req);
+               sizev6 = sizeof(struct cpl_act_open_req6);
+               break;
+       case CHELSIO_T5:
+               sizev4 = sizeof(struct cpl_t5_act_open_req);
+               sizev6 = sizeof(struct cpl_t5_act_open_req6);
+               break;
+       case CHELSIO_T6:
+               sizev4 = sizeof(struct cpl_t6_act_open_req);
+               sizev6 = sizeof(struct cpl_t6_act_open_req6);
+               break;
+       default:
+               pr_err("T%d Chip is not supported\n",
+                      CHELSIO_CHIP_VERSION(adapter_type));
+               return -EINVAL;
+       }
 
        wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
                        roundup(sizev4, 16) :
@@ -706,7 +722,10 @@ static int send_connect(struct c4iw_ep *ep)
                opt2 |= SACK_EN_F;
        if (wscale && enable_tcp_window_scaling)
                opt2 |= WND_SCALE_EN_F;
-       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
+       if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
+               if (peer2peer)
+                       isn += 4;
+
                opt2 |= T5_OPT_2_VALID_F;
                opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
                opt2 |= T5_ISS_F;
@@ -718,102 +737,109 @@ static int send_connect(struct c4iw_ep *ep)
 
        t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);
 
-       if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
-               if (ep->com.remote_addr.ss_family == AF_INET) {
-                       req = (struct cpl_act_open_req *) skb_put(skb, wrlen);
+       if (ep->com.remote_addr.ss_family == AF_INET) {
+               switch (CHELSIO_CHIP_VERSION(adapter_type)) {
+               case CHELSIO_T4:
+                       req = (struct cpl_act_open_req *)skb_put(skb, wrlen);
                        INIT_TP_WR(req, 0);
-                       OPCODE_TID(req) = cpu_to_be32(
-                                       MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
-                                       ((ep->rss_qid << 14) | ep->atid)));
-                       req->local_port = la->sin_port;
-                       req->peer_port = ra->sin_port;
-                       req->local_ip = la->sin_addr.s_addr;
-                       req->peer_ip = ra->sin_addr.s_addr;
-                       req->opt0 = cpu_to_be64(opt0);
+                       break;
+               case CHELSIO_T5:
+                       t5req = (struct cpl_t5_act_open_req *)skb_put(skb,
+                                       wrlen);
+                       INIT_TP_WR(t5req, 0);
+                       req = (struct cpl_act_open_req *)t5req;
+                       break;
+               case CHELSIO_T6:
+                       t6req = (struct cpl_t6_act_open_req *)skb_put(skb,
+                                       wrlen);
+                       INIT_TP_WR(t6req, 0);
+                       req = (struct cpl_act_open_req *)t6req;
+                       t5req = (struct cpl_t5_act_open_req *)t6req;
+                       break;
+               default:
+                       pr_err("T%d Chip is not supported\n",
+                              CHELSIO_CHIP_VERSION(adapter_type));
+                       ret = -EINVAL;
+                       goto clip_release;
+               }
+
+               OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
+                                       ((ep->rss_qid<<14) | ep->atid)));
+               req->local_port = la->sin_port;
+               req->peer_port = ra->sin_port;
+               req->local_ip = la->sin_addr.s_addr;
+               req->peer_ip = ra->sin_addr.s_addr;
+               req->opt0 = cpu_to_be64(opt0);
+
+               if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
                        req->params = cpu_to_be32(cxgb4_select_ntuple(
                                                ep->com.dev->rdev.lldi.ports[0],
                                                ep->l2t));
                        req->opt2 = cpu_to_be32(opt2);
                } else {
+                       t5req->params = cpu_to_be64(FILTER_TUPLE_V(
+                                               cxgb4_select_ntuple(
+                                               ep->com.dev->rdev.lldi.ports[0],
+                                               ep->l2t)));
+                       t5req->rsvd = cpu_to_be32(isn);
+                       PDBG("%s snd_isn %u\n", __func__, t5req->rsvd);
+                       t5req->opt2 = cpu_to_be32(opt2);
+               }
+       } else {
+               switch (CHELSIO_CHIP_VERSION(adapter_type)) {
+               case CHELSIO_T4:
                        req6 = (struct cpl_act_open_req6 *)skb_put(skb, wrlen);
-
                        INIT_TP_WR(req6, 0);
-                       OPCODE_TID(req6) = cpu_to_be32(
-                                          MK_OPCODE_TID(CPL_ACT_OPEN_REQ6,
-                                          ((ep->rss_qid<<14)|ep->atid)));
-                       req6->local_port = la6->sin6_port;
-                       req6->peer_port = ra6->sin6_port;
-                       req6->local_ip_hi = *((__be64 *)
-                                               (la6->sin6_addr.s6_addr));
-                       req6->local_ip_lo = *((__be64 *)
-                                               (la6->sin6_addr.s6_addr + 8));
-                       req6->peer_ip_hi = *((__be64 *)
-                                               (ra6->sin6_addr.s6_addr));
-                       req6->peer_ip_lo = *((__be64 *)
-                                               (ra6->sin6_addr.s6_addr + 8));
-                       req6->opt0 = cpu_to_be64(opt0);
+                       break;
+               case CHELSIO_T5:
+                       t5req6 = (struct cpl_t5_act_open_req6 *)skb_put(skb,
+                                       wrlen);
+                       INIT_TP_WR(t5req6, 0);
+                       req6 = (struct cpl_act_open_req6 *)t5req6;
+                       break;
+               case CHELSIO_T6:
+                       t6req6 = (struct cpl_t6_act_open_req6 *)skb_put(skb,
+                                       wrlen);
+                       INIT_TP_WR(t6req6, 0);
+                       req6 = (struct cpl_act_open_req6 *)t6req6;
+                       t5req6 = (struct cpl_t5_act_open_req6 *)t6req6;
+                       break;
+               default:
+                       pr_err("T%d Chip is not supported\n",
+                              CHELSIO_CHIP_VERSION(adapter_type));
+                       ret = -EINVAL;
+                       goto clip_release;
+               }
+
+               OPCODE_TID(req6) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6,
+                                       ((ep->rss_qid<<14)|ep->atid)));
+               req6->local_port = la6->sin6_port;
+               req6->peer_port = ra6->sin6_port;
+               req6->local_ip_hi = *((__be64 *)(la6->sin6_addr.s6_addr));
+               req6->local_ip_lo = *((__be64 *)(la6->sin6_addr.s6_addr + 8));
+               req6->peer_ip_hi = *((__be64 *)(ra6->sin6_addr.s6_addr));
+               req6->peer_ip_lo = *((__be64 *)(ra6->sin6_addr.s6_addr + 8));
+               req6->opt0 = cpu_to_be64(opt0);
+
+               if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
                        req6->params = cpu_to_be32(cxgb4_select_ntuple(
                                                ep->com.dev->rdev.lldi.ports[0],
                                                ep->l2t));
                        req6->opt2 = cpu_to_be32(opt2);
-               }
-       } else {
-               u32 isn = (prandom_u32() & ~7UL) - 1;
-
-               if (peer2peer)
-                       isn += 4;
-
-               if (ep->com.remote_addr.ss_family == AF_INET) {
-                       t5_req = (struct cpl_t5_act_open_req *)
-                                skb_put(skb, wrlen);
-                       INIT_TP_WR(t5_req, 0);
-                       OPCODE_TID(t5_req) = cpu_to_be32(
-                                       MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
-                                       ((ep->rss_qid << 14) | ep->atid)));
-                       t5_req->local_port = la->sin_port;
-                       t5_req->peer_port = ra->sin_port;
-                       t5_req->local_ip = la->sin_addr.s_addr;
-                       t5_req->peer_ip = ra->sin_addr.s_addr;
-                       t5_req->opt0 = cpu_to_be64(opt0);
-                       t5_req->params = cpu_to_be64(FILTER_TUPLE_V(
-                                                    cxgb4_select_ntuple(
-                                            ep->com.dev->rdev.lldi.ports[0],
-                                            ep->l2t)));
-                       t5_req->rsvd = cpu_to_be32(isn);
-                       PDBG("%s snd_isn %u\n", __func__,
-                            be32_to_cpu(t5_req->rsvd));
-                       t5_req->opt2 = cpu_to_be32(opt2);
                } else {
-                       t5_req6 = (struct cpl_t5_act_open_req6 *)
-                                 skb_put(skb, wrlen);
-                       INIT_TP_WR(t5_req6, 0);
-                       OPCODE_TID(t5_req6) = cpu_to_be32(
-                                             MK_OPCODE_TID(CPL_ACT_OPEN_REQ6,
-                                             ((ep->rss_qid<<14)|ep->atid)));
-                       t5_req6->local_port = la6->sin6_port;
-                       t5_req6->peer_port = ra6->sin6_port;
-                       t5_req6->local_ip_hi = *((__be64 *)
-                                               (la6->sin6_addr.s6_addr));
-                       t5_req6->local_ip_lo = *((__be64 *)
-                                               (la6->sin6_addr.s6_addr + 8));
-                       t5_req6->peer_ip_hi = *((__be64 *)
-                                               (ra6->sin6_addr.s6_addr));
-                       t5_req6->peer_ip_lo = *((__be64 *)
-                                               (ra6->sin6_addr.s6_addr + 8));
-                       t5_req6->opt0 = cpu_to_be64(opt0);
-                       t5_req6->params = cpu_to_be64(FILTER_TUPLE_V(
-                                                       cxgb4_select_ntuple(
+                       t5req6->params = cpu_to_be64(FILTER_TUPLE_V(
+                                               cxgb4_select_ntuple(
                                                ep->com.dev->rdev.lldi.ports[0],
                                                ep->l2t)));
-                       t5_req6->rsvd = cpu_to_be32(isn);
-                       PDBG("%s snd_isn %u\n", __func__,
-                            be32_to_cpu(t5_req6->rsvd));
-                       t5_req6->opt2 = cpu_to_be32(opt2);
+                       t5req6->rsvd = cpu_to_be32(isn);
+                       PDBG("%s snd_isn %u\n", __func__, t5req6->rsvd);
+                       t5req6->opt2 = cpu_to_be32(opt2);
                }
        }
 
        set_bit(ACT_OPEN_REQ, &ep->com.history);
        ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+clip_release:
        if (ret && ep->com.remote_addr.ss_family == AF_INET6)
                cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
                                   (const u32 *)&la6->sin6_addr.s6_addr, 1);
@@ -1196,6 +1222,8 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
        if ((status == 0) || (status == -ECONNREFUSED)) {
                if (!ep->tried_with_mpa_v1) {
                        /* this means MPA_v2 is used */
+                       event.ord = ep->ird;
+                       event.ird = ep->ord;
                        event.private_data_len = ep->plen -
                                sizeof(struct mpa_v2_conn_params);
                        event.private_data = ep->mpa_pkt +
@@ -1203,6 +1231,8 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
                                sizeof(struct mpa_v2_conn_params);
                } else {
                        /* this means MPA_v1 is used */
+                       event.ord = cur_max_read_depth(ep->com.dev);
+                       event.ird = cur_max_read_depth(ep->com.dev);
                        event.private_data_len = ep->plen;
                        event.private_data = ep->mpa_pkt +
                                sizeof(struct mpa_message);
@@ -1265,8 +1295,8 @@ static void established_upcall(struct c4iw_ep *ep)
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        memset(&event, 0, sizeof(event));
        event.event = IW_CM_EVENT_ESTABLISHED;
-       event.ird = ep->ird;
-       event.ord = ep->ord;
+       event.ird = ep->ord;
+       event.ord = ep->ird;
        if (ep->com.cm_id) {
                PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
                ep->com.cm_id->event_handler(ep->com.cm_id, &event);
@@ -1898,7 +1928,7 @@ static void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi)
 
 static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
                     struct dst_entry *dst, struct c4iw_dev *cdev,
-                    bool clear_mpa_v1)
+                    bool clear_mpa_v1, enum chip_type adapter_type)
 {
        struct neighbour *n;
        int err, step;
@@ -1933,7 +1963,8 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
                        goto out;
                ep->mtu = pdev->mtu;
                ep->tx_chan = cxgb4_port_chan(pdev);
-               ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
+               ep->smac_idx = cxgb4_tp_smt_idx(adapter_type,
+                                               cxgb4_port_viid(pdev));
                step = cdev->rdev.lldi.ntxq /
                        cdev->rdev.lldi.nchan;
                ep->txq_idx = cxgb4_port_idx(pdev) * step;
@@ -1952,7 +1983,8 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
                        goto out;
                ep->mtu = dst_mtu(dst);
                ep->tx_chan = cxgb4_port_chan(pdev);
-               ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
+               ep->smac_idx = cxgb4_tp_smt_idx(adapter_type,
+                                               cxgb4_port_viid(pdev));
                step = cdev->rdev.lldi.ntxq /
                        cdev->rdev.lldi.nchan;
                ep->txq_idx = cxgb4_port_idx(pdev) * step;
@@ -2025,7 +2057,8 @@ static int c4iw_reconnect(struct c4iw_ep *ep)
                err = -EHOSTUNREACH;
                goto fail3;
        }
-       err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, false);
+       err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, false,
+                       ep->com.dev->rdev.lldi.adapter_type);
        if (err) {
                pr_err("%s - cannot alloc l2e.\n", __func__);
                goto fail4;
@@ -2213,13 +2246,14 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
        int wscale;
        struct cpl_t5_pass_accept_rpl *rpl5 = NULL;
        int win;
+       enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        BUG_ON(skb_cloned(skb));
 
        skb_get(skb);
        rpl = cplhdr(skb);
-       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
+       if (!is_t4(adapter_type)) {
                skb_trim(skb, roundup(sizeof(*rpl5), 16));
                rpl5 = (void *)rpl;
                INIT_TP_WR(rpl5, ep->hwtid);
@@ -2266,12 +2300,16 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
                const struct tcphdr *tcph;
                u32 hlen = ntohl(req->hdr_len);
 
-               tcph = (const void *)(req + 1) + ETH_HDR_LEN_G(hlen) +
-                       IP_HDR_LEN_G(hlen);
+               if (CHELSIO_CHIP_VERSION(adapter_type) <= CHELSIO_T5)
+                       tcph = (const void *)(req + 1) + ETH_HDR_LEN_G(hlen) +
+                               IP_HDR_LEN_G(hlen);
+               else
+                       tcph = (const void *)(req + 1) +
+                               T6_ETH_HDR_LEN_G(hlen) + T6_IP_HDR_LEN_G(hlen);
                if (tcph->ece && tcph->cwr)
                        opt2 |= CCTRL_ECN_V(1);
        }
-       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
+       if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
                u32 isn = (prandom_u32() & ~7UL) - 1;
                opt2 |= T5_OPT_2_VALID_F;
                opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
@@ -2302,12 +2340,16 @@ static void reject_cr(struct c4iw_dev *dev, u32 hwtid, struct sk_buff *skb)
        return;
 }
 
-static void get_4tuple(struct cpl_pass_accept_req *req, int *iptype,
-                      __u8 *local_ip, __u8 *peer_ip,
+static void get_4tuple(struct cpl_pass_accept_req *req, enum chip_type type,
+                      int *iptype, __u8 *local_ip, __u8 *peer_ip,
                       __be16 *local_port, __be16 *peer_port)
 {
-       int eth_len = ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len));
-       int ip_len = IP_HDR_LEN_G(be32_to_cpu(req->hdr_len));
+       int eth_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ?
+                     ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)) :
+                     T6_ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len));
+       int ip_len = (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) ?
+                    IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)) :
+                    T6_IP_HDR_LEN_G(be32_to_cpu(req->hdr_len));
        struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len);
        struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len);
        struct tcphdr *tcp = (struct tcphdr *)
@@ -2362,7 +2404,8 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
                goto reject;
        }
 
-       get_4tuple(req, &iptype, local_ip, peer_ip, &local_port, &peer_port);
+       get_4tuple(req, parent_ep->com.dev->rdev.lldi.adapter_type, &iptype,
+                  local_ip, peer_ip, &local_port, &peer_port);
 
        /* Find output route */
        if (iptype == 4)  {
@@ -2397,7 +2440,8 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
                goto reject;
        }
 
-       err = import_ep(child_ep, iptype, peer_ip, dst, dev, false);
+       err = import_ep(child_ep, iptype, peer_ip, dst, dev, false,
+                       parent_ep->com.dev->rdev.lldi.adapter_type);
        if (err) {
                printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
                       __func__);
@@ -2929,7 +2973,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        } else {
                if (peer2peer &&
                    (ep->mpa_attr.p2p_type != FW_RI_INIT_P2PTYPE_DISABLED) &&
-                   (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) && ep->ord == 0)
+                   (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) && ep->ird == 0)
                        ep->ird = 1;
        }
 
@@ -3189,7 +3233,8 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                goto fail2;
        }
 
-       err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true);
+       err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true,
+                       ep->com.dev->rdev.lldi.adapter_type);
        if (err) {
                printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
                goto fail3;
@@ -3260,6 +3305,10 @@ static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
                                sin->sin_addr.s_addr, sin->sin_port, 0,
                                ep->com.dev->rdev.lldi.rxq_ids[0], 0, 0);
                        if (err == -EBUSY) {
+                               if (c4iw_fatal_error(&ep->com.dev->rdev)) {
+                                       err = -EIO;
+                                       break;
+                               }
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                schedule_timeout(usecs_to_jiffies(100));
                        }
@@ -3593,20 +3642,23 @@ static int deferred_fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
 
 static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
 {
-       u32 l2info;
-       u16 vlantag, len, hdr_len, eth_hdr_len;
+       __be32 l2info;
+       __be16 hdr_len, vlantag, len;
+       u16 eth_hdr_len;
+       int tcp_hdr_len, ip_hdr_len;
        u8 intf;
        struct cpl_rx_pkt *cpl = cplhdr(skb);
        struct cpl_pass_accept_req *req;
        struct tcp_options_received tmp_opt;
        struct c4iw_dev *dev;
+       enum chip_type type;
 
        dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
        /* Store values from cpl_rx_pkt in temporary location. */
-       vlantag = (__force u16) cpl->vlan;
-       len = (__force u16) cpl->len;
-       l2info  = (__force u32) cpl->l2info;
-       hdr_len = (__force u16) cpl->hdr_len;
+       vlantag = cpl->vlan;
+       len = cpl->len;
+       l2info  = cpl->l2info;
+       hdr_len = cpl->hdr_len;
        intf = cpl->iff;
 
        __skb_pull(skb, sizeof(*req) + sizeof(struct rss_header));
@@ -3623,20 +3675,28 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
        memset(req, 0, sizeof(*req));
        req->l2info = cpu_to_be16(SYN_INTF_V(intf) |
                         SYN_MAC_IDX_V(RX_MACIDX_G(
-                        (__force int) htonl(l2info))) |
+                        be32_to_cpu(l2info))) |
                         SYN_XACT_MATCH_F);
-       eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
-                           RX_ETHHDR_LEN_G((__force int)htonl(l2info)) :
-                           RX_T5_ETHHDR_LEN_G((__force int)htonl(l2info));
-       req->hdr_len = cpu_to_be32(SYN_RX_CHAN_V(RX_CHAN_G(
-                                       (__force int) htonl(l2info))) |
-                                  TCP_HDR_LEN_V(RX_TCPHDR_LEN_G(
-                                       (__force int) htons(hdr_len))) |
-                                  IP_HDR_LEN_V(RX_IPHDR_LEN_G(
-                                       (__force int) htons(hdr_len))) |
-                                  ETH_HDR_LEN_V(RX_ETHHDR_LEN_G(eth_hdr_len)));
-       req->vlan = (__force __be16) vlantag;
-       req->len = (__force __be16) len;
+       type = dev->rdev.lldi.adapter_type;
+       tcp_hdr_len = RX_TCPHDR_LEN_G(be16_to_cpu(hdr_len));
+       ip_hdr_len = RX_IPHDR_LEN_G(be16_to_cpu(hdr_len));
+       req->hdr_len =
+               cpu_to_be32(SYN_RX_CHAN_V(RX_CHAN_G(be32_to_cpu(l2info))));
+       if (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) {
+               eth_hdr_len = is_t4(type) ?
+                               RX_ETHHDR_LEN_G(be32_to_cpu(l2info)) :
+                               RX_T5_ETHHDR_LEN_G(be32_to_cpu(l2info));
+               req->hdr_len |= cpu_to_be32(TCP_HDR_LEN_V(tcp_hdr_len) |
+                                           IP_HDR_LEN_V(ip_hdr_len) |
+                                           ETH_HDR_LEN_V(eth_hdr_len));
+       } else { /* T6 and later */
+               eth_hdr_len = RX_T6_ETHHDR_LEN_G(be32_to_cpu(l2info));
+               req->hdr_len |= cpu_to_be32(T6_TCP_HDR_LEN_V(tcp_hdr_len) |
+                                           T6_IP_HDR_LEN_V(ip_hdr_len) |
+                                           T6_ETH_HDR_LEN_V(eth_hdr_len));
+       }
+       req->vlan = vlantag;
+       req->len = len;
        req->tos_stid = cpu_to_be32(PASS_OPEN_TID_V(stid) |
                                    PASS_OPEN_TOS_V(tos));
        req->tcpopt.mss = htons(tmp_opt.mss_clamp);
@@ -3755,9 +3815,22 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
                goto reject;
        }
 
-       eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
-                           RX_ETHHDR_LEN_G(htonl(cpl->l2info)) :
-                           RX_T5_ETHHDR_LEN_G(htonl(cpl->l2info));
+       switch (CHELSIO_CHIP_VERSION(dev->rdev.lldi.adapter_type)) {
+       case CHELSIO_T4:
+               eth_hdr_len = RX_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
+               break;
+       case CHELSIO_T5:
+               eth_hdr_len = RX_T5_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
+               break;
+       case CHELSIO_T6:
+               eth_hdr_len = RX_T6_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
+               break;
+       default:
+               pr_err("T%d Chip is not supported\n",
+                      CHELSIO_CHIP_VERSION(dev->rdev.lldi.adapter_type));
+               goto reject;
+       }
+
        if (eth_hdr_len == ETH_HLEN) {
                eh = (struct ethhdr *)(req + 1);
                iph = (struct iphdr *)(eh + 1);
index 92d518382a9fce90c3e1dbae45034675072da274..de9cd6901752fc1e3da38d64f62bfce7cb853501 100644 (file)
@@ -752,7 +752,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
                        wc->opcode = IB_WC_LOCAL_INV;
                        break;
                case FW_RI_FAST_REGISTER:
-                       wc->opcode = IB_WC_FAST_REG_MR;
+                       wc->opcode = IB_WC_REG_MR;
                        break;
                default:
                        printk(KERN_ERR MOD "Unexpected opcode %d "
index 1a297391b54c16c3a954650b57ef164ee471ca57..58fce1742b8d8c33b91dfa89075617a9c5cf34f7 100644 (file)
@@ -962,12 +962,12 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
                devp->rdev.lldi.sge_egrstatuspagesize;
 
        /*
-        * For T5 devices, we map all of BAR2 with WC.
+        * For T5/T6 devices, we map all of BAR2 with WC.
         * For T4 devices with onchip qp mem, we map only that part
         * of BAR2 with WC.
         */
        devp->rdev.bar2_pa = pci_resource_start(devp->rdev.lldi.pdev, 2);
-       if (is_t5(devp->rdev.lldi.adapter_type)) {
+       if (!is_t4(devp->rdev.lldi.adapter_type)) {
                devp->rdev.bar2_kva = ioremap_wc(devp->rdev.bar2_pa,
                        pci_resource_len(devp->rdev.lldi.pdev, 2));
                if (!devp->rdev.bar2_kva) {
@@ -1267,11 +1267,9 @@ static int enable_qp_db(int id, void *p, void *data)
 static void resume_rc_qp(struct c4iw_qp *qp)
 {
        spin_lock(&qp->lock);
-       t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc,
-                     is_t5(qp->rhp->rdev.lldi.adapter_type), NULL);
+       t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc, NULL);
        qp->wq.sq.wq_pidx_inc = 0;
-       t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc,
-                     is_t5(qp->rhp->rdev.lldi.adapter_type), NULL);
+       t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc, NULL);
        qp->wq.rq.wq_pidx_inc = 0;
        spin_unlock(&qp->lock);
 }
index c7bb38c931a555b034e76580484d79851dd7546c..00e55faa086aa2a30259c5c8b96cc0ae129a4ef6 100644 (file)
@@ -386,6 +386,10 @@ struct c4iw_mr {
        struct c4iw_dev *rhp;
        u64 kva;
        struct tpt_attributes attr;
+       u64 *mpl;
+       dma_addr_t mpl_addr;
+       u32 max_mpl_len;
+       u32 mpl_len;
 };
 
 static inline struct c4iw_mr *to_c4iw_mr(struct ib_mr *ibmr)
@@ -405,20 +409,6 @@ static inline struct c4iw_mw *to_c4iw_mw(struct ib_mw *ibmw)
        return container_of(ibmw, struct c4iw_mw, ibmw);
 }
 
-struct c4iw_fr_page_list {
-       struct ib_fast_reg_page_list ibpl;
-       DEFINE_DMA_UNMAP_ADDR(mapping);
-       dma_addr_t dma_addr;
-       struct c4iw_dev *dev;
-       int pll_len;
-};
-
-static inline struct c4iw_fr_page_list *to_c4iw_fr_page_list(
-                                       struct ib_fast_reg_page_list *ibpl)
-{
-       return container_of(ibpl, struct c4iw_fr_page_list, ibpl);
-}
-
 struct c4iw_cq {
        struct ib_cq ibcq;
        struct c4iw_dev *rhp;
@@ -966,13 +956,12 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
 int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len);
 void c4iw_qp_add_ref(struct ib_qp *qp);
 void c4iw_qp_rem_ref(struct ib_qp *qp);
-void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *page_list);
-struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(
-                                       struct ib_device *device,
-                                       int page_list_len);
 struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
                            enum ib_mr_type mr_type,
                            u32 max_num_sg);
+int c4iw_map_mr_sg(struct ib_mr *ibmr,
+                  struct scatterlist *sg,
+                  int sg_nents);
 int c4iw_dealloc_mw(struct ib_mw *mw);
 struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type);
 struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start,
index 026b91ebd5e2e6806acae6b81dd41d56d599b4d2..e1629ab58db7873a3d9a6c044ba7bc65eb4512c6 100644 (file)
@@ -144,7 +144,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
                if (i == (num_wqe-1)) {
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
                                                    FW_WR_COMPL_F);
-                       req->wr.wr_lo = (__force __be64)&wr_wait;
+                       req->wr.wr_lo = (__force __be64)(unsigned long)&wr_wait;
                } else
                        req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
                req->wr.wr_mid = cpu_to_be32(
@@ -863,6 +863,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
        u32 mmid;
        u32 stag = 0;
        int ret = 0;
+       int length = roundup(max_num_sg * sizeof(u64), 32);
 
        if (mr_type != IB_MR_TYPE_MEM_REG ||
            max_num_sg > t4_max_fr_depth(use_dsgl))
@@ -876,6 +877,14 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
                goto err;
        }
 
+       mhp->mpl = dma_alloc_coherent(&rhp->rdev.lldi.pdev->dev,
+                                     length, &mhp->mpl_addr, GFP_KERNEL);
+       if (!mhp->mpl) {
+               ret = -ENOMEM;
+               goto err_mpl;
+       }
+       mhp->max_mpl_len = length;
+
        mhp->rhp = rhp;
        ret = alloc_pbl(mhp, max_num_sg);
        if (ret)
@@ -905,54 +914,35 @@ err2:
        c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
                              mhp->attr.pbl_size << 3);
 err1:
+       dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
+                         mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
+err_mpl:
        kfree(mhp);
 err:
        return ERR_PTR(ret);
 }
 
-struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device,
-                                                    int page_list_len)
+static int c4iw_set_page(struct ib_mr *ibmr, u64 addr)
 {
-       struct c4iw_fr_page_list *c4pl;
-       struct c4iw_dev *dev = to_c4iw_dev(device);
-       dma_addr_t dma_addr;
-       int pll_len = roundup(page_list_len * sizeof(u64), 32);
-
-       c4pl = kmalloc(sizeof(*c4pl), GFP_KERNEL);
-       if (!c4pl)
-               return ERR_PTR(-ENOMEM);
+       struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
 
-       c4pl->ibpl.page_list = dma_alloc_coherent(&dev->rdev.lldi.pdev->dev,
-                                                 pll_len, &dma_addr,
-                                                 GFP_KERNEL);
-       if (!c4pl->ibpl.page_list) {
-               kfree(c4pl);
-               return ERR_PTR(-ENOMEM);
-       }
-       dma_unmap_addr_set(c4pl, mapping, dma_addr);
-       c4pl->dma_addr = dma_addr;
-       c4pl->dev = dev;
-       c4pl->pll_len = pll_len;
+       if (unlikely(mhp->mpl_len == mhp->max_mpl_len))
+               return -ENOMEM;
 
-       PDBG("%s c4pl %p pll_len %u page_list %p dma_addr %pad\n",
-            __func__, c4pl, c4pl->pll_len, c4pl->ibpl.page_list,
-            &c4pl->dma_addr);
+       mhp->mpl[mhp->mpl_len++] = addr;
 
-       return &c4pl->ibpl;
+       return 0;
 }
 
-void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *ibpl)
+int c4iw_map_mr_sg(struct ib_mr *ibmr,
+                  struct scatterlist *sg,
+                  int sg_nents)
 {
-       struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl);
+       struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
 
-       PDBG("%s c4pl %p pll_len %u page_list %p dma_addr %pad\n",
-            __func__, c4pl, c4pl->pll_len, c4pl->ibpl.page_list,
-            &c4pl->dma_addr);
+       mhp->mpl_len = 0;
 
-       dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev,
-                         c4pl->pll_len,
-                         c4pl->ibpl.page_list, dma_unmap_addr(c4pl, mapping));
-       kfree(c4pl);
+       return ib_sg_to_pages(ibmr, sg, sg_nents, c4iw_set_page);
 }
 
 int c4iw_dereg_mr(struct ib_mr *ib_mr)
@@ -970,6 +960,9 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
        rhp = mhp->rhp;
        mmid = mhp->attr.stag >> 8;
        remove_handle(rhp, &rhp->mmidr, mmid);
+       if (mhp->mpl)
+               dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
+                                 mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
        dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
                       mhp->attr.pbl_addr);
        if (mhp->attr.pbl_size)
index 7746113552e7b37cb38907c38dc5b4fca7fdebd4..0a7d99818b17d13384e32cb81446bd250647f85f 100644 (file)
@@ -209,7 +209,7 @@ static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
                if (addr >= rdev->oc_mw_pa)
                        vma->vm_page_prot = t4_pgprot_wc(vma->vm_page_prot);
                else {
-                       if (is_t5(rdev->lldi.adapter_type))
+                       if (!is_t4(rdev->lldi.adapter_type))
                                vma->vm_page_prot =
                                        t4_pgprot_wc(vma->vm_page_prot);
                        else
@@ -557,8 +557,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
        dev->ibdev.bind_mw = c4iw_bind_mw;
        dev->ibdev.dealloc_mw = c4iw_dealloc_mw;
        dev->ibdev.alloc_mr = c4iw_alloc_mr;
-       dev->ibdev.alloc_fast_reg_page_list = c4iw_alloc_fastreg_pbl;
-       dev->ibdev.free_fast_reg_page_list = c4iw_free_fastreg_pbl;
+       dev->ibdev.map_mr_sg = c4iw_map_mr_sg;
        dev->ibdev.attach_mcast = c4iw_multicast_attach;
        dev->ibdev.detach_mcast = c4iw_multicast_detach;
        dev->ibdev.process_mad = c4iw_process_mad;
index 6517e1208ccb42dc38cd551a971e531e2eb7cd51..aa515afee7248823428cb2b725bf10c70f4fd82a 100644 (file)
@@ -528,8 +528,8 @@ static int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
        if (wr->num_sge > T4_MAX_SEND_SGE)
                return -EINVAL;
        wqe->write.r2 = 0;
-       wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);
-       wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);
+       wqe->write.stag_sink = cpu_to_be32(rdma_wr(wr)->rkey);
+       wqe->write.to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr);
        if (wr->num_sge) {
                if (wr->send_flags & IB_SEND_INLINE) {
                        ret = build_immd(sq, wqe->write.u.immd_src, wr,
@@ -566,10 +566,10 @@ static int build_rdma_read(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
        if (wr->num_sge > 1)
                return -EINVAL;
        if (wr->num_sge) {
-               wqe->read.stag_src = cpu_to_be32(wr->wr.rdma.rkey);
-               wqe->read.to_src_hi = cpu_to_be32((u32)(wr->wr.rdma.remote_addr
+               wqe->read.stag_src = cpu_to_be32(rdma_wr(wr)->rkey);
+               wqe->read.to_src_hi = cpu_to_be32((u32)(rdma_wr(wr)->remote_addr
                                                        >> 32));
-               wqe->read.to_src_lo = cpu_to_be32((u32)wr->wr.rdma.remote_addr);
+               wqe->read.to_src_lo = cpu_to_be32((u32)rdma_wr(wr)->remote_addr);
                wqe->read.stag_sink = cpu_to_be32(wr->sg_list[0].lkey);
                wqe->read.plen = cpu_to_be32(wr->sg_list[0].length);
                wqe->read.to_sink_hi = cpu_to_be32((u32)(wr->sg_list[0].addr
@@ -605,47 +605,41 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
        return 0;
 }
 
-static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
-                        struct ib_send_wr *wr, u8 *len16, u8 t5dev)
+static int build_memreg(struct t4_sq *sq, union t4_wr *wqe,
+                       struct ib_reg_wr *wr, u8 *len16, u8 t5dev)
 {
-
+       struct c4iw_mr *mhp = to_c4iw_mr(wr->mr);
        struct fw_ri_immd *imdp;
        __be64 *p;
        int i;
-       int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
+       int pbllen = roundup(mhp->mpl_len * sizeof(u64), 32);
        int rem;
 
-       if (wr->wr.fast_reg.page_list_len >
-           t4_max_fr_depth(use_dsgl))
+       if (mhp->mpl_len > t4_max_fr_depth(use_dsgl))
                return -EINVAL;
 
        wqe->fr.qpbinde_to_dcacpu = 0;
-       wqe->fr.pgsz_shift = wr->wr.fast_reg.page_shift - 12;
+       wqe->fr.pgsz_shift = ilog2(wr->mr->page_size) - 12;
        wqe->fr.addr_type = FW_RI_VA_BASED_TO;
-       wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->wr.fast_reg.access_flags);
+       wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->access);
        wqe->fr.len_hi = 0;
-       wqe->fr.len_lo = cpu_to_be32(wr->wr.fast_reg.length);
-       wqe->fr.stag = cpu_to_be32(wr->wr.fast_reg.rkey);
-       wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
-       wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
+       wqe->fr.len_lo = cpu_to_be32(mhp->ibmr.length);
+       wqe->fr.stag = cpu_to_be32(wr->key);
+       wqe->fr.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32);
+       wqe->fr.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova &
                                        0xffffffff);
 
        if (t5dev && use_dsgl && (pbllen > max_fr_immd)) {
-               struct c4iw_fr_page_list *c4pl =
-                       to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
                struct fw_ri_dsgl *sglp;
 
-               for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-                       wr->wr.fast_reg.page_list->page_list[i] = (__force u64)
-                               cpu_to_be64((u64)
-                               wr->wr.fast_reg.page_list->page_list[i]);
-               }
+               for (i = 0; i < mhp->mpl_len; i++)
+                       mhp->mpl[i] = (__force u64)cpu_to_be64((u64)mhp->mpl[i]);
 
                sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
                sglp->op = FW_RI_DATA_DSGL;
                sglp->r1 = 0;
                sglp->nsge = cpu_to_be16(1);
-               sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
+               sglp->addr0 = cpu_to_be64(mhp->mpl_addr);
                sglp->len0 = cpu_to_be32(pbllen);
 
                *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16);
@@ -657,9 +651,8 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
                imdp->immdlen = cpu_to_be32(pbllen);
                p = (__be64 *)(imdp + 1);
                rem = pbllen;
-               for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-                       *p = cpu_to_be64(
-                               (u64)wr->wr.fast_reg.page_list->page_list[i]);
+               for (i = 0; i < mhp->mpl_len; i++) {
+                       *p = cpu_to_be64((u64)mhp->mpl[i]);
                        rem -= sizeof(*p);
                        if (++p == (__be64 *)&sq->queue[sq->size])
                                p = (__be64 *)sq->queue;
@@ -712,8 +705,7 @@ static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
        spin_lock_irqsave(&qhp->rhp->lock, flags);
        spin_lock(&qhp->lock);
        if (qhp->rhp->db_state == NORMAL)
-               t4_ring_sq_db(&qhp->wq, inc,
-                             is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL);
+               t4_ring_sq_db(&qhp->wq, inc, NULL);
        else {
                add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
                qhp->wq.sq.wq_pidx_inc += inc;
@@ -730,8 +722,7 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
        spin_lock_irqsave(&qhp->rhp->lock, flags);
        spin_lock(&qhp->lock);
        if (qhp->rhp->db_state == NORMAL)
-               t4_ring_rq_db(&qhp->wq, inc,
-                             is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL);
+               t4_ring_rq_db(&qhp->wq, inc, NULL);
        else {
                add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
                qhp->wq.rq.wq_pidx_inc += inc;
@@ -813,13 +804,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        if (!qhp->wq.sq.oldest_read)
                                qhp->wq.sq.oldest_read = swsqe;
                        break;
-               case IB_WR_FAST_REG_MR:
+               case IB_WR_REG_MR:
                        fw_opcode = FW_RI_FR_NSMR_WR;
                        swsqe->opcode = FW_RI_FAST_REGISTER;
-                       err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16,
-                                           is_t5(
-                                           qhp->rhp->rdev.lldi.adapter_type) ?
-                                           1 : 0);
+                       err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr), &len16,
+                                          is_t5(
+                                          qhp->rhp->rdev.lldi.adapter_type) ?
+                                          1 : 0);
                        break;
                case IB_WR_LOCAL_INV:
                        if (wr->send_flags & IB_SEND_FENCE)
@@ -860,8 +851,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
        }
        if (!qhp->rhp->rdev.status_page->db_off) {
-               t4_ring_sq_db(&qhp->wq, idx,
-                             is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe);
+               t4_ring_sq_db(&qhp->wq, idx, wqe);
                spin_unlock_irqrestore(&qhp->lock, flag);
        } else {
                spin_unlock_irqrestore(&qhp->lock, flag);
@@ -934,8 +924,7 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                num_wrs--;
        }
        if (!qhp->rhp->rdev.status_page->db_off) {
-               t4_ring_rq_db(&qhp->wq, idx,
-                             is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe);
+               t4_ring_rq_db(&qhp->wq, idx, wqe);
                spin_unlock_irqrestore(&qhp->lock, flag);
        } else {
                spin_unlock_irqrestore(&qhp->lock, flag);
@@ -1875,7 +1864,7 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        attrs.rq_db_inc = attr->rq_psn;
        mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0;
        mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0;
-       if (is_t5(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) &&
+       if (!is_t4(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) &&
            (mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB)))
                return -EINVAL;
 
index 274a7ab13befb367cedae3618a29e2ba0591b72a..1092a2d1f607464152fbd2d7e836e180d2131312 100644 (file)
@@ -455,8 +455,7 @@ static inline void pio_copy(u64 __iomem *dst, u64 *src)
        }
 }
 
-static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5,
-                                union t4_wr *wqe)
+static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, union t4_wr *wqe)
 {
 
        /* Flush host queue memory writes. */
@@ -482,7 +481,7 @@ static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5,
        writel(QID_V(wq->sq.qid) | PIDX_V(inc), wq->db);
 }
 
-static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5,
+static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc,
                                 union t4_recv_wr *wqe)
 {
 
index 1688a17de4fe1fc6d887d74d703b51dffaff2e08..86af71351d9a5be6cbdd87f3d22ccb7078c82b23 100644 (file)
@@ -76,7 +76,10 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
        struct mlx4_dev *dev = ibdev->dev;
        int is_mcast = 0;
        struct in6_addr in6;
-       u16 vlan_tag;
+       u16 vlan_tag = 0xffff;
+       union ib_gid sgid;
+       struct ib_gid_attr gid_attr;
+       int ret;
 
        memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6));
        if (rdma_is_multicast_addr(&in6)) {
@@ -85,7 +88,17 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
        } else {
                memcpy(ah->av.eth.mac, ah_attr->dmac, ETH_ALEN);
        }
-       vlan_tag = ah_attr->vlan_id;
+       ret = ib_get_cached_gid(pd->device, ah_attr->port_num,
+                               ah_attr->grh.sgid_index, &sgid, &gid_attr);
+       if (ret)
+               return ERR_PTR(ret);
+       memset(ah->av.eth.s_mac, 0, ETH_ALEN);
+       if (gid_attr.ndev) {
+               if (is_vlan_dev(gid_attr.ndev))
+                       vlan_tag = vlan_dev_vlan_id(gid_attr.ndev);
+               memcpy(ah->av.eth.s_mac, gid_attr.ndev->dev_addr, ETH_ALEN);
+               dev_put(gid_attr.ndev);
+       }
        if (vlan_tag < 0x1000)
                vlan_tag |= (ah_attr->sl & 7) << 13;
        ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
index 5fd49f9435f9dd8d2496d91394271b6270af2cbd..b88fc8f5ab180c717e827f582187b817f92a0e33 100644 (file)
@@ -818,7 +818,7 @@ repoll:
                        wc->opcode    = IB_WC_LSO;
                        break;
                case MLX4_OPCODE_FMR:
-                       wc->opcode    = IB_WC_FAST_REG_MR;
+                       wc->opcode    = IB_WC_REG_MR;
                        break;
                case MLX4_OPCODE_LOCAL_INVAL:
                        wc->opcode    = IB_WC_LOCAL_INV;
index 1cd75ff0225193c475c9a9debe2ccedcf9bdb8b8..870e56b6b25f5c7837f5a4a358597d748aaf1ef5 100644 (file)
@@ -457,7 +457,8 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
                          struct ib_grh *grh, struct ib_mad *mad)
 {
        struct ib_sge list;
-       struct ib_send_wr wr, *bad_wr;
+       struct ib_ud_wr wr;
+       struct ib_send_wr *bad_wr;
        struct mlx4_ib_demux_pv_ctx *tun_ctx;
        struct mlx4_ib_demux_pv_qp *tun_qp;
        struct mlx4_rcv_tunnel_mad *tun_mad;
@@ -582,18 +583,18 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
        list.length = sizeof (struct mlx4_rcv_tunnel_mad);
        list.lkey = tun_ctx->pd->local_dma_lkey;
 
-       wr.wr.ud.ah = ah;
-       wr.wr.ud.port_num = port;
-       wr.wr.ud.remote_qkey = IB_QP_SET_QKEY;
-       wr.wr.ud.remote_qpn = dqpn;
-       wr.next = NULL;
-       wr.wr_id = ((u64) tun_tx_ix) | MLX4_TUN_SET_WRID_QPN(dest_qpt);
-       wr.sg_list = &list;
-       wr.num_sge = 1;
-       wr.opcode = IB_WR_SEND;
-       wr.send_flags = IB_SEND_SIGNALED;
-
-       ret = ib_post_send(src_qp, &wr, &bad_wr);
+       wr.ah = ah;
+       wr.port_num = port;
+       wr.remote_qkey = IB_QP_SET_QKEY;
+       wr.remote_qpn = dqpn;
+       wr.wr.next = NULL;
+       wr.wr.wr_id = ((u64) tun_tx_ix) | MLX4_TUN_SET_WRID_QPN(dest_qpt);
+       wr.wr.sg_list = &list;
+       wr.wr.num_sge = 1;
+       wr.wr.opcode = IB_WR_SEND;
+       wr.wr.send_flags = IB_SEND_SIGNALED;
+
+       ret = ib_post_send(src_qp, &wr.wr, &bad_wr);
 out:
        if (ret)
                ib_destroy_ah(ah);
@@ -824,18 +825,29 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
 {
        struct mlx4_counter counter_stats;
        struct mlx4_ib_dev *dev = to_mdev(ibdev);
-       int err;
+       struct counter_index *tmp_counter;
+       int err = IB_MAD_RESULT_FAILURE, stats_avail = 0;
 
        if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
                return -EINVAL;
 
        memset(&counter_stats, 0, sizeof(counter_stats));
-       err = mlx4_get_counter_stats(dev->dev,
-                                    dev->counters[port_num - 1].index,
-                                    &counter_stats, 0);
-       if (err)
-               err = IB_MAD_RESULT_FAILURE;
-       else {
+       mutex_lock(&dev->counters_table[port_num - 1].mutex);
+       list_for_each_entry(tmp_counter,
+                           &dev->counters_table[port_num - 1].counters_list,
+                           list) {
+               err = mlx4_get_counter_stats(dev->dev,
+                                            tmp_counter->index,
+                                            &counter_stats, 0);
+               if (err) {
+                       err = IB_MAD_RESULT_FAILURE;
+                       stats_avail = 0;
+                       break;
+               }
+               stats_avail = 1;
+       }
+       mutex_unlock(&dev->counters_table[port_num - 1].mutex);
+       if (stats_avail) {
                memset(out_mad->data, 0, sizeof out_mad->data);
                switch (counter_stats.counter_mode & 0xf) {
                case 0:
@@ -1172,10 +1184,11 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave)
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
                         enum ib_qp_type dest_qpt, u16 pkey_index,
                         u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr,
-                        u8 *s_mac, struct ib_mad *mad)
+                        u8 *s_mac, u16 vlan_id, struct ib_mad *mad)
 {
        struct ib_sge list;
-       struct ib_send_wr wr, *bad_wr;
+       struct ib_ud_wr wr;
+       struct ib_send_wr *bad_wr;
        struct mlx4_ib_demux_pv_ctx *sqp_ctx;
        struct mlx4_ib_demux_pv_qp *sqp;
        struct mlx4_mad_snd_buf *sqp_mad;
@@ -1246,22 +1259,25 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
        list.length = sizeof (struct mlx4_mad_snd_buf);
        list.lkey = sqp_ctx->pd->local_dma_lkey;
 
-       wr.wr.ud.ah = ah;
-       wr.wr.ud.port_num = port;
-       wr.wr.ud.pkey_index = wire_pkey_ix;
-       wr.wr.ud.remote_qkey = qkey;
-       wr.wr.ud.remote_qpn = remote_qpn;
-       wr.next = NULL;
-       wr.wr_id = ((u64) wire_tx_ix) | MLX4_TUN_SET_WRID_QPN(src_qpnum);
-       wr.sg_list = &list;
-       wr.num_sge = 1;
-       wr.opcode = IB_WR_SEND;
-       wr.send_flags = IB_SEND_SIGNALED;
+       wr.ah = ah;
+       wr.port_num = port;
+       wr.pkey_index = wire_pkey_ix;
+       wr.remote_qkey = qkey;
+       wr.remote_qpn = remote_qpn;
+       wr.wr.next = NULL;
+       wr.wr.wr_id = ((u64) wire_tx_ix) | MLX4_TUN_SET_WRID_QPN(src_qpnum);
+       wr.wr.sg_list = &list;
+       wr.wr.num_sge = 1;
+       wr.wr.opcode = IB_WR_SEND;
+       wr.wr.send_flags = IB_SEND_SIGNALED;
        if (s_mac)
                memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6);
+       if (vlan_id < 0x1000)
+               vlan_id |= (attr->sl & 7) << 13;
+       to_mah(ah)->av.eth.vlan = cpu_to_be16(vlan_id);
 
 
-       ret = ib_post_send(send_qp, &wr, &bad_wr);
+       ret = ib_post_send(send_qp, &wr.wr, &bad_wr);
 out:
        if (ret)
                ib_destroy_ah(ah);
@@ -1295,6 +1311,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
        u8 *slave_id;
        int slave;
        int port;
+       u16 vlan_id;
 
        /* Get slave that sent this packet */
        if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn ||
@@ -1383,10 +1400,10 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
                fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr);
 
        memcpy(ah_attr.dmac, tunnel->hdr.mac, 6);
-       ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan);
+       vlan_id = be16_to_cpu(tunnel->hdr.vlan);
        /* if slave have default vlan use it */
        mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave,
-                                   &ah_attr.vlan_id, &ah_attr.sl);
+                                   &vlan_id, &ah_attr.sl);
 
        mlx4_ib_send_to_wire(dev, slave, ctx->port,
                             is_proxy_qp0(dev, wc->src_qp, slave) ?
@@ -1394,7 +1411,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
                             be16_to_cpu(tunnel->hdr.pkey_index),
                             be32_to_cpu(tunnel->hdr.remote_qpn),
                             be32_to_cpu(tunnel->hdr.qkey),
-                            &ah_attr, wc->smac, &tunnel->mad);
+                            &ah_attr, wc->smac, vlan_id, &tunnel->mad);
 }
 
 static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
index efecdf0216d85179c05f6e949d0c7597cf7f4f70..f567160a4a56ed141320b2d153d21f2031cbb464 100644 (file)
@@ -335,7 +335,7 @@ int mlx4_ib_gid_index_to_real_index(struct mlx4_ib_dev *ibdev,
        if (!rdma_cap_roce_gid_table(&ibdev->ib_dev, port_num))
                return index;
 
-       ret = ib_get_cached_gid(&ibdev->ib_dev, port_num, index, &gid);
+       ret = ib_get_cached_gid(&ibdev->ib_dev, port_num, index, &gid, NULL);
        if (ret)
                return ret;
 
@@ -442,6 +442,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
                props->device_cap_flags |= IB_DEVICE_MANAGED_FLOW_STEERING;
        }
 
+       props->device_cap_flags |= IB_DEVICE_RAW_IP_CSUM;
+
        props->vendor_id           = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
                0xffffff;
        props->vendor_part_id      = dev->dev->persist->pdev->device;
@@ -754,7 +756,7 @@ static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
        if (!rdma_cap_roce_gid_table(ibdev, port))
                return -ENODEV;
 
-       ret = ib_get_cached_gid(ibdev, port, index, gid);
+       ret = ib_get_cached_gid(ibdev, port, index, gid, NULL);
        if (ret == -EAGAIN) {
                memcpy(gid, &zgid, sizeof(*gid));
                return 0;
@@ -1247,6 +1249,22 @@ static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
        return 0;
 }
 
+static void mlx4_ib_delete_counters_table(struct mlx4_ib_dev *ibdev,
+                                         struct mlx4_ib_counters *ctr_table)
+{
+       struct counter_index *counter, *tmp_count;
+
+       mutex_lock(&ctr_table->mutex);
+       list_for_each_entry_safe(counter, tmp_count, &ctr_table->counters_list,
+                                list) {
+               if (counter->allocated)
+                       mlx4_counter_free(ibdev->dev, counter->index);
+               list_del(&counter->list);
+               kfree(counter);
+       }
+       mutex_unlock(&ctr_table->mutex);
+}
+
 int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
                   union ib_gid *gid)
 {
@@ -2131,6 +2149,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        int num_req_counters;
        int allocated;
        u32 counter_index;
+       struct counter_index *new_counter_index = NULL;
 
        pr_info_once("%s", mlx4_ib_version);
 
@@ -2247,8 +2266,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        ibdev->ib_dev.rereg_user_mr     = mlx4_ib_rereg_user_mr;
        ibdev->ib_dev.dereg_mr          = mlx4_ib_dereg_mr;
        ibdev->ib_dev.alloc_mr          = mlx4_ib_alloc_mr;
-       ibdev->ib_dev.alloc_fast_reg_page_list = mlx4_ib_alloc_fast_reg_page_list;
-       ibdev->ib_dev.free_fast_reg_page_list  = mlx4_ib_free_fast_reg_page_list;
+       ibdev->ib_dev.map_mr_sg         = mlx4_ib_map_mr_sg;
        ibdev->ib_dev.attach_mcast      = mlx4_ib_mcg_attach;
        ibdev->ib_dev.detach_mcast      = mlx4_ib_mcg_detach;
        ibdev->ib_dev.process_mad       = mlx4_ib_process_mad;
@@ -2293,7 +2311,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
 
        ibdev->ib_dev.uverbs_ex_cmd_mask |=
                (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE) |
-               (1ull << IB_USER_VERBS_EX_CMD_CREATE_CQ);
+               (1ull << IB_USER_VERBS_EX_CMD_CREATE_CQ) |
+               (1ull << IB_USER_VERBS_EX_CMD_CREATE_QP);
 
        mlx4_ib_alloc_eqs(dev, ibdev);
 
@@ -2302,6 +2321,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        if (init_node_data(ibdev))
                goto err_map;
 
+       for (i = 0; i < ibdev->num_ports; ++i) {
+               mutex_init(&ibdev->counters_table[i].mutex);
+               INIT_LIST_HEAD(&ibdev->counters_table[i].counters_list);
+       }
+
        num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports;
        for (i = 0; i < num_req_counters; ++i) {
                mutex_init(&ibdev->qp1_proxy_lock[i]);
@@ -2320,15 +2344,34 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                        counter_index = mlx4_get_default_counter_index(dev,
                                                                       i + 1);
                }
-               ibdev->counters[i].index = counter_index;
-               ibdev->counters[i].allocated = allocated;
+               new_counter_index = kmalloc(sizeof(*new_counter_index),
+                                           GFP_KERNEL);
+               if (!new_counter_index) {
+                       if (allocated)
+                               mlx4_counter_free(ibdev->dev, counter_index);
+                       goto err_counter;
+               }
+               new_counter_index->index = counter_index;
+               new_counter_index->allocated = allocated;
+               list_add_tail(&new_counter_index->list,
+                             &ibdev->counters_table[i].counters_list);
+               ibdev->counters_table[i].default_counter = counter_index;
                pr_info("counter index %d for port %d allocated %d\n",
                        counter_index, i + 1, allocated);
        }
        if (mlx4_is_bonded(dev))
                for (i = 1; i < ibdev->num_ports ; ++i) {
-                       ibdev->counters[i].index = ibdev->counters[0].index;
-                       ibdev->counters[i].allocated = 0;
+                       new_counter_index =
+                                       kmalloc(sizeof(struct counter_index),
+                                               GFP_KERNEL);
+                       if (!new_counter_index)
+                               goto err_counter;
+                       new_counter_index->index = counter_index;
+                       new_counter_index->allocated = 0;
+                       list_add_tail(&new_counter_index->list,
+                                     &ibdev->counters_table[i].counters_list);
+                       ibdev->counters_table[i].default_counter =
+                                                               counter_index;
                }
 
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
@@ -2437,12 +2480,9 @@ err_steer_qp_release:
                mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
                                      ibdev->steer_qpn_count);
 err_counter:
-       for (i = 0; i < ibdev->num_ports; ++i) {
-               if (ibdev->counters[i].index != -1 &&
-                   ibdev->counters[i].allocated)
-                       mlx4_counter_free(ibdev->dev,
-                                         ibdev->counters[i].index);
-       }
+       for (i = 0; i < ibdev->num_ports; ++i)
+               mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
+
 err_map:
        iounmap(ibdev->uar_map);
 
@@ -2546,9 +2586,8 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
 
        iounmap(ibdev->uar_map);
        for (p = 0; p < ibdev->num_ports; ++p)
-               if (ibdev->counters[p].index != -1 &&
-                   ibdev->counters[p].allocated)
-                       mlx4_counter_free(ibdev->dev, ibdev->counters[p].index);
+               mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[p]);
+
        mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
                mlx4_CLOSE_PORT(dev, p);
 
index 2d5bccd71fc66d121382326655a4180db1692e0b..99451d887266d2bffee04e2a71347f69b4883305 100644 (file)
@@ -222,7 +222,7 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad)
        spin_unlock_irqrestore(&dev->sm_lock, flags);
        return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev),
                                    ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY,
-                                   &ah_attr, NULL, mad);
+                                   &ah_attr, NULL, 0xffff, mad);
 }
 
 static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx,
index 1e7b23bb2eb0bbb4b95c737585ace30371003494..1caa11edac03347a246467436daa72dd18d5c505 100644 (file)
@@ -129,10 +129,17 @@ struct mlx4_ib_cq {
        struct list_head                recv_qp_list;
 };
 
+#define MLX4_MR_PAGES_ALIGN 0x40
+
 struct mlx4_ib_mr {
        struct ib_mr            ibmr;
+       __be64                  *pages;
+       dma_addr_t              page_map;
+       u32                     npages;
+       u32                     max_pages;
        struct mlx4_mr          mmr;
        struct ib_umem         *umem;
+       void                    *pages_alloc;
 };
 
 struct mlx4_ib_mw {
@@ -140,12 +147,6 @@ struct mlx4_ib_mw {
        struct mlx4_mw          mmw;
 };
 
-struct mlx4_ib_fast_reg_page_list {
-       struct ib_fast_reg_page_list    ibfrpl;
-       __be64                         *mapped_page_list;
-       dma_addr_t                      map;
-};
-
 struct mlx4_ib_fmr {
        struct ib_fmr           ibfmr;
        struct mlx4_fmr         mfmr;
@@ -320,6 +321,7 @@ struct mlx4_ib_qp {
        struct list_head        qps_list;
        struct list_head        cq_recv_list;
        struct list_head        cq_send_list;
+       struct counter_index    *counter_index;
 };
 
 struct mlx4_ib_srq {
@@ -528,10 +530,17 @@ struct mlx4_ib_iov_port {
 };
 
 struct counter_index {
+       struct  list_head       list;
        u32             index;
        u8              allocated;
 };
 
+struct mlx4_ib_counters {
+       struct list_head        counters_list;
+       struct mutex            mutex; /* mutex for accessing counters list */
+       u32                     default_counter;
+};
+
 struct mlx4_ib_dev {
        struct ib_device        ib_dev;
        struct mlx4_dev        *dev;
@@ -550,7 +559,7 @@ struct mlx4_ib_dev {
        struct mutex            cap_mask_mutex;
        bool                    ib_active;
        struct mlx4_ib_iboe     iboe;
-       struct counter_index    counters[MLX4_MAX_PORTS];
+       struct mlx4_ib_counters counters_table[MLX4_MAX_PORTS];
        int                    *eq_table;
        struct kobject         *iov_parent;
        struct kobject         *ports_parent;
@@ -638,11 +647,6 @@ static inline struct mlx4_ib_mw *to_mmw(struct ib_mw *ibmw)
        return container_of(ibmw, struct mlx4_ib_mw, ibmw);
 }
 
-static inline struct mlx4_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl)
-{
-       return container_of(ibfrpl, struct mlx4_ib_fast_reg_page_list, ibfrpl);
-}
-
 static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
 {
        return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr);
@@ -706,10 +710,9 @@ int mlx4_ib_dealloc_mw(struct ib_mw *mw);
 struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd,
                               enum ib_mr_type mr_type,
                               u32 max_num_sg);
-struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
-                                                              int page_list_len);
-void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list);
-
+int mlx4_ib_map_mr_sg(struct ib_mr *ibmr,
+                     struct scatterlist *sg,
+                     int sg_nents);
 int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);
 int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
 struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
@@ -813,7 +816,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
                         enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
                         u32 qkey, struct ib_ah_attr *attr, u8 *s_mac,
-                        struct ib_mad *mad);
+                        u16 vlan_id, struct ib_mad *mad);
 
 __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx);
 
index 2542fd3c1a493e037d6b1e24a4d5b15176ca03f9..4d1e1c632603a7b81e6685cd5ad6020f98a02a47 100644 (file)
@@ -59,7 +59,7 @@ struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc)
        struct mlx4_ib_mr *mr;
        int err;
 
-       mr = kmalloc(sizeof *mr, GFP_KERNEL);
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
@@ -140,7 +140,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        int err;
        int n;
 
-       mr = kmalloc(sizeof *mr, GFP_KERNEL);
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
@@ -271,11 +271,59 @@ release_mpt_entry:
        return err;
 }
 
+static int
+mlx4_alloc_priv_pages(struct ib_device *device,
+                     struct mlx4_ib_mr *mr,
+                     int max_pages)
+{
+       int size = max_pages * sizeof(u64);
+       int add_size;
+       int ret;
+
+       add_size = max_t(int, MLX4_MR_PAGES_ALIGN - ARCH_KMALLOC_MINALIGN, 0);
+
+       mr->pages_alloc = kzalloc(size + add_size, GFP_KERNEL);
+       if (!mr->pages_alloc)
+               return -ENOMEM;
+
+       mr->pages = PTR_ALIGN(mr->pages_alloc, MLX4_MR_PAGES_ALIGN);
+
+       mr->page_map = dma_map_single(device->dma_device, mr->pages,
+                                     size, DMA_TO_DEVICE);
+
+       if (dma_mapping_error(device->dma_device, mr->page_map)) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(mr->pages_alloc);
+
+       return ret;
+}
+
+static void
+mlx4_free_priv_pages(struct mlx4_ib_mr *mr)
+{
+       if (mr->pages) {
+               struct ib_device *device = mr->ibmr.device;
+               int size = mr->max_pages * sizeof(u64);
+
+               dma_unmap_single(device->dma_device, mr->page_map,
+                                size, DMA_TO_DEVICE);
+               kfree(mr->pages_alloc);
+               mr->pages = NULL;
+       }
+}
+
 int mlx4_ib_dereg_mr(struct ib_mr *ibmr)
 {
        struct mlx4_ib_mr *mr = to_mmr(ibmr);
        int ret;
 
+       mlx4_free_priv_pages(mr);
+
        ret = mlx4_mr_free(to_mdev(ibmr->device)->dev, &mr->mmr);
        if (ret)
                return ret;
@@ -321,21 +369,21 @@ err_free:
 int mlx4_ib_bind_mw(struct ib_qp *qp, struct ib_mw *mw,
                    struct ib_mw_bind *mw_bind)
 {
-       struct ib_send_wr  wr;
+       struct ib_bind_mw_wr  wr;
        struct ib_send_wr *bad_wr;
        int ret;
 
        memset(&wr, 0, sizeof(wr));
-       wr.opcode               = IB_WR_BIND_MW;
-       wr.wr_id                = mw_bind->wr_id;
-       wr.send_flags           = mw_bind->send_flags;
-       wr.wr.bind_mw.mw        = mw;
-       wr.wr.bind_mw.bind_info = mw_bind->bind_info;
-       wr.wr.bind_mw.rkey      = ib_inc_rkey(mw->rkey);
-
-       ret = mlx4_ib_post_send(qp, &wr, &bad_wr);
+       wr.wr.opcode            = IB_WR_BIND_MW;
+       wr.wr.wr_id             = mw_bind->wr_id;
+       wr.wr.send_flags        = mw_bind->send_flags;
+       wr.mw                   = mw;
+       wr.bind_info            = mw_bind->bind_info;
+       wr.rkey                 = ib_inc_rkey(mw->rkey);
+
+       ret = mlx4_ib_post_send(qp, &wr.wr, &bad_wr);
        if (!ret)
-               mw->rkey = wr.wr.bind_mw.rkey;
+               mw->rkey = wr.rkey;
 
        return ret;
 }
@@ -362,7 +410,7 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd,
            max_num_sg > MLX4_MAX_FAST_REG_PAGES)
                return ERR_PTR(-EINVAL);
 
-       mr = kmalloc(sizeof *mr, GFP_KERNEL);
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
@@ -371,71 +419,30 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd,
        if (err)
                goto err_free;
 
+       err = mlx4_alloc_priv_pages(pd->device, mr, max_num_sg);
+       if (err)
+               goto err_free_mr;
+
+       mr->max_pages = max_num_sg;
+
        err = mlx4_mr_enable(dev->dev, &mr->mmr);
        if (err)
-               goto err_mr;
+               goto err_free_pl;
 
        mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key;
        mr->umem = NULL;
 
        return &mr->ibmr;
 
-err_mr:
+err_free_pl:
+       mlx4_free_priv_pages(mr);
+err_free_mr:
        (void) mlx4_mr_free(dev->dev, &mr->mmr);
-
 err_free:
        kfree(mr);
        return ERR_PTR(err);
 }
 
-struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
-                                                              int page_list_len)
-{
-       struct mlx4_ib_dev *dev = to_mdev(ibdev);
-       struct mlx4_ib_fast_reg_page_list *mfrpl;
-       int size = page_list_len * sizeof (u64);
-
-       if (page_list_len > MLX4_MAX_FAST_REG_PAGES)
-               return ERR_PTR(-EINVAL);
-
-       mfrpl = kmalloc(sizeof *mfrpl, GFP_KERNEL);
-       if (!mfrpl)
-               return ERR_PTR(-ENOMEM);
-
-       mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL);
-       if (!mfrpl->ibfrpl.page_list)
-               goto err_free;
-
-       mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->persist->
-                                                    pdev->dev,
-                                                    size, &mfrpl->map,
-                                                    GFP_KERNEL);
-       if (!mfrpl->mapped_page_list)
-               goto err_free;
-
-       WARN_ON(mfrpl->map & 0x3f);
-
-       return &mfrpl->ibfrpl;
-
-err_free:
-       kfree(mfrpl->ibfrpl.page_list);
-       kfree(mfrpl);
-       return ERR_PTR(-ENOMEM);
-}
-
-void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
-{
-       struct mlx4_ib_dev *dev = to_mdev(page_list->device);
-       struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list);
-       int size = page_list->max_page_list_len * sizeof (u64);
-
-       dma_free_coherent(&dev->dev->persist->pdev->dev, size,
-                         mfrpl->mapped_page_list,
-                         mfrpl->map);
-       kfree(mfrpl->ibfrpl.page_list);
-       kfree(mfrpl);
-}
-
 struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc,
                                 struct ib_fmr_attr *fmr_attr)
 {
@@ -528,3 +535,37 @@ int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr)
 
        return err;
 }
+
+static int mlx4_set_page(struct ib_mr *ibmr, u64 addr)
+{
+       struct mlx4_ib_mr *mr = to_mmr(ibmr);
+
+       if (unlikely(mr->npages == mr->max_pages))
+               return -ENOMEM;
+
+       mr->pages[mr->npages++] = cpu_to_be64(addr | MLX4_MTT_FLAG_PRESENT);
+
+       return 0;
+}
+
+int mlx4_ib_map_mr_sg(struct ib_mr *ibmr,
+                     struct scatterlist *sg,
+                     int sg_nents)
+{
+       struct mlx4_ib_mr *mr = to_mmr(ibmr);
+       int rc;
+
+       mr->npages = 0;
+
+       ib_dma_sync_single_for_cpu(ibmr->device, mr->page_map,
+                                  sizeof(u64) * mr->max_pages,
+                                  DMA_TO_DEVICE);
+
+       rc = ib_sg_to_pages(ibmr, sg, sg_nents, mlx4_set_page);
+
+       ib_dma_sync_single_for_device(ibmr->device, mr->page_map,
+                                     sizeof(u64) * mr->max_pages,
+                                     DMA_TO_DEVICE);
+
+       return rc;
+}
index 4ad9be3ad61c0a780be7c0ce9aa098989226c77e..a2e4ca56da44e5d9cec5ee4b6a02cf6ab9d7356c 100644 (file)
@@ -111,7 +111,7 @@ static const __be32 mlx4_ib_opcode[] = {
        [IB_WR_ATOMIC_FETCH_AND_ADD]            = cpu_to_be32(MLX4_OPCODE_ATOMIC_FA),
        [IB_WR_SEND_WITH_INV]                   = cpu_to_be32(MLX4_OPCODE_SEND_INVAL),
        [IB_WR_LOCAL_INV]                       = cpu_to_be32(MLX4_OPCODE_LOCAL_INVAL),
-       [IB_WR_FAST_REG_MR]                     = cpu_to_be32(MLX4_OPCODE_FMR),
+       [IB_WR_REG_MR]                          = cpu_to_be32(MLX4_OPCODE_FMR),
        [IB_WR_MASKED_ATOMIC_CMP_AND_SWP]       = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_CS),
        [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]     = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_FA),
        [IB_WR_BIND_MW]                         = cpu_to_be32(MLX4_OPCODE_BIND_MW),
@@ -617,6 +617,18 @@ static int qp0_enabled_vf(struct mlx4_dev *dev, int qpn)
        return 0;
 }
 
+static void mlx4_ib_free_qp_counter(struct mlx4_ib_dev *dev,
+                                   struct mlx4_ib_qp *qp)
+{
+       mutex_lock(&dev->counters_table[qp->port - 1].mutex);
+       mlx4_counter_free(dev->dev, qp->counter_index->index);
+       list_del(&qp->counter_index->list);
+       mutex_unlock(&dev->counters_table[qp->port - 1].mutex);
+
+       kfree(qp->counter_index);
+       qp->counter_index = NULL;
+}
+
 static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                            struct ib_qp_init_attr *init_attr,
                            struct ib_udata *udata, int sqpn, struct mlx4_ib_qp **caller_qp,
@@ -746,9 +758,6 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        } else {
                qp->sq_no_prefetch = 0;
 
-               if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
-                       qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
-
                if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
                        qp->flags |= MLX4_IB_QP_LSO;
 
@@ -822,6 +831,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                        goto err_proxy;
        }
 
+       if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
+               qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
+
        err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp, gfp);
        if (err)
                goto err_qpn;
@@ -1086,6 +1098,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
 {
        struct mlx4_ib_qp *qp = NULL;
        int err;
+       int sup_u_create_flags = MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
        u16 xrcdn = 0;
        gfp_t gfp;
 
@@ -1109,8 +1122,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
        }
 
        if (init_attr->create_flags &&
-           (udata ||
-            ((init_attr->create_flags & ~(MLX4_IB_SRIOV_SQP | MLX4_IB_QP_CREATE_USE_GFP_NOIO)) &&
+           ((udata && init_attr->create_flags & ~(sup_u_create_flags)) ||
+            ((init_attr->create_flags & ~(MLX4_IB_SRIOV_SQP |
+                                          MLX4_IB_QP_CREATE_USE_GFP_NOIO |
+                                          MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK)) &&
              init_attr->qp_type != IB_QPT_UD) ||
             ((init_attr->create_flags & MLX4_IB_SRIOV_SQP) &&
              init_attr->qp_type > IB_QPT_GSI)))
@@ -1189,6 +1204,9 @@ int mlx4_ib_destroy_qp(struct ib_qp *qp)
                mutex_unlock(&dev->qp1_proxy_lock[mqp->port - 1]);
        }
 
+       if (mqp->counter_index)
+               mlx4_ib_free_qp_counter(dev, mqp);
+
        pd = get_pd(mqp);
        destroy_qp_common(dev, mqp, !!pd->ibpd.uobject);
 
@@ -1391,11 +1409,12 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
 static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp,
                         enum ib_qp_attr_mask qp_attr_mask,
                         struct mlx4_ib_qp *mqp,
-                        struct mlx4_qp_path *path, u8 port)
+                        struct mlx4_qp_path *path, u8 port,
+                        u16 vlan_id, u8 *smac)
 {
        return _mlx4_set_path(dev, &qp->ah_attr,
-                             mlx4_mac_to_u64((u8 *)qp->smac),
-                             (qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff,
+                             mlx4_mac_to_u64(smac),
+                             vlan_id,
                              path, &mqp->pri, port);
 }
 
@@ -1406,9 +1425,8 @@ static int mlx4_set_alt_path(struct mlx4_ib_dev *dev,
                             struct mlx4_qp_path *path, u8 port)
 {
        return _mlx4_set_path(dev, &qp->alt_ah_attr,
-                             mlx4_mac_to_u64((u8 *)qp->alt_smac),
-                             (qp_attr_mask & IB_QP_ALT_VID) ?
-                             qp->alt_vlan_id : 0xffff,
+                             0,
+                             0xffff,
                              path, &mqp->alt, port);
 }
 
@@ -1424,7 +1442,8 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
        }
 }
 
-static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac,
+static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev,
+                                   struct mlx4_ib_qp *qp,
                                    struct mlx4_qp_context *context)
 {
        u64 u64_mac;
@@ -1447,6 +1466,40 @@ static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *
        return 0;
 }
 
+static int create_qp_lb_counter(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
+{
+       struct counter_index *new_counter_index;
+       int err;
+       u32 tmp_idx;
+
+       if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) !=
+           IB_LINK_LAYER_ETHERNET ||
+           !(qp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) ||
+           !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK))
+               return 0;
+
+       err = mlx4_counter_alloc(dev->dev, &tmp_idx);
+       if (err)
+               return err;
+
+       new_counter_index = kmalloc(sizeof(*new_counter_index), GFP_KERNEL);
+       if (!new_counter_index) {
+               mlx4_counter_free(dev->dev, tmp_idx);
+               return -ENOMEM;
+       }
+
+       new_counter_index->index = tmp_idx;
+       new_counter_index->allocated = 1;
+       qp->counter_index = new_counter_index;
+
+       mutex_lock(&dev->counters_table[qp->port - 1].mutex);
+       list_add_tail(&new_counter_index->list,
+                     &dev->counters_table[qp->port - 1].counters_list);
+       mutex_unlock(&dev->counters_table[qp->port - 1].mutex);
+
+       return 0;
+}
+
 static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                               const struct ib_qp_attr *attr, int attr_mask,
                               enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -1460,6 +1513,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        int sqd_event;
        int steer_qp = 0;
        int err = -EINVAL;
+       int counter_index;
 
        /* APM is not supported under RoCE */
        if (attr_mask & IB_QP_ALT_PATH &&
@@ -1519,6 +1573,9 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3;
        context->sq_size_stride |= qp->sq.wqe_shift - 4;
 
+       if (new_state == IB_QPS_RESET && qp->counter_index)
+               mlx4_ib_free_qp_counter(dev, qp);
+
        if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
                context->sq_size_stride |= !!qp->sq_no_prefetch << 7;
                context->xrcd = cpu_to_be32((u32) qp->xrcdn);
@@ -1543,10 +1600,24 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
-               if (dev->counters[qp->port - 1].index != -1) {
-                       context->pri_path.counter_index =
-                                       dev->counters[qp->port - 1].index;
+               err = create_qp_lb_counter(dev, qp);
+               if (err)
+                       goto out;
+
+               counter_index =
+                       dev->counters_table[qp->port - 1].default_counter;
+               if (qp->counter_index)
+                       counter_index = qp->counter_index->index;
+
+               if (counter_index != -1) {
+                       context->pri_path.counter_index = counter_index;
                        optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX;
+                       if (qp->counter_index) {
+                               context->pri_path.fl |=
+                                       MLX4_FL_ETH_SRC_CHECK_MC_LB;
+                               context->pri_path.vlan_control |=
+                                       MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
+                       }
                } else
                        context->pri_path.counter_index =
                                MLX4_SINK_COUNTER_INDEX(dev->dev);
@@ -1565,9 +1636,33 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_AV) {
+               u8 port_num = mlx4_is_bonded(to_mdev(ibqp->device)->dev) ? 1 :
+                       attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
+               union ib_gid gid;
+               struct ib_gid_attr gid_attr;
+               u16 vlan = 0xffff;
+               u8 smac[ETH_ALEN];
+               int status = 0;
+
+               if (rdma_cap_eth_ah(&dev->ib_dev, port_num) &&
+                   attr->ah_attr.ah_flags & IB_AH_GRH) {
+                       int index = attr->ah_attr.grh.sgid_index;
+
+                       status = ib_get_cached_gid(ibqp->device, port_num,
+                                                  index, &gid, &gid_attr);
+                       if (!status && !memcmp(&gid, &zgid, sizeof(gid)))
+                               status = -ENOENT;
+                       if (!status && gid_attr.ndev) {
+                               vlan = rdma_vlan_dev_vlan_id(gid_attr.ndev);
+                               memcpy(smac, gid_attr.ndev->dev_addr, ETH_ALEN);
+                               dev_put(gid_attr.ndev);
+                       }
+               }
+               if (status)
+                       goto out;
+
                if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path,
-                                 attr_mask & IB_QP_PORT ?
-                                 attr->port_num : qp->port))
+                                 port_num, vlan, smac))
                        goto out;
 
                optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
@@ -1704,7 +1799,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                        if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD ||
                            qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
                            qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
-                               err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
+                               err = handle_eth_ud_smac_index(dev, qp, context);
                                if (err) {
                                        err = -EINVAL;
                                        goto out;
@@ -1848,6 +1943,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                }
        }
 out:
+       if (err && qp->counter_index)
+               mlx4_ib_free_qp_counter(dev, qp);
        if (err && steer_qp)
                mlx4_ib_steer_qp_reg(dev, qp, 0);
        kfree(context);
@@ -2036,14 +2133,14 @@ static int vf_get_qp0_qkey(struct mlx4_dev *dev, int qpn, u32 *qkey)
 }
 
 static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
-                                 struct ib_send_wr *wr,
+                                 struct ib_ud_wr *wr,
                                  void *wqe, unsigned *mlx_seg_len)
 {
        struct mlx4_ib_dev *mdev = to_mdev(sqp->qp.ibqp.device);
        struct ib_device *ib_dev = &mdev->ib_dev;
        struct mlx4_wqe_mlx_seg *mlx = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
-       struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       struct mlx4_ib_ah *ah = to_mah(wr->ah);
        u16 pkey;
        u32 qkey;
        int send_size;
@@ -2051,13 +2148,13 @@ static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
        int spc;
        int i;
 
-       if (wr->opcode != IB_WR_SEND)
+       if (wr->wr.opcode != IB_WR_SEND)
                return -EINVAL;
 
        send_size = 0;
 
-       for (i = 0; i < wr->num_sge; ++i)
-               send_size += wr->sg_list[i].length;
+       for (i = 0; i < wr->wr.num_sge; ++i)
+               send_size += wr->wr.sg_list[i].length;
 
        /* for proxy-qp0 sends, need to add in size of tunnel header */
        /* for tunnel-qp0 sends, tunnel header is already in s/g list */
@@ -2082,11 +2179,11 @@ static int build_sriov_qp0_header(struct mlx4_ib_sqp *sqp,
        mlx->rlid = sqp->ud_header.lrh.destination_lid;
 
        sqp->ud_header.lrh.virtual_lane    = 0;
-       sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
+       sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
        ib_get_cached_pkey(ib_dev, sqp->qp.port, 0, &pkey);
        sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
        if (sqp->qp.mlx4_ib_qp_type == MLX4_IB_QPT_TUN_SMI_OWNER)
-               sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+               sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
        else
                sqp->ud_header.bth.destination_qpn =
                        cpu_to_be32(mdev->dev->caps.qp0_tunnel[sqp->qp.port - 1]);
@@ -2158,14 +2255,14 @@ static void mlx4_u64_to_smac(u8 *dst_mac, u64 src_mac)
        }
 }
 
-static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
+static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_ud_wr *wr,
                            void *wqe, unsigned *mlx_seg_len)
 {
        struct ib_device *ib_dev = sqp->qp.ibqp.device;
        struct mlx4_wqe_mlx_seg *mlx = wqe;
        struct mlx4_wqe_ctrl_seg *ctrl = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
-       struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       struct mlx4_ib_ah *ah = to_mah(wr->ah);
        union ib_gid sgid;
        u16 pkey;
        int send_size;
@@ -2179,8 +2276,8 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        bool is_grh;
 
        send_size = 0;
-       for (i = 0; i < wr->num_sge; ++i)
-               send_size += wr->sg_list[i].length;
+       for (i = 0; i < wr->wr.num_sge; ++i)
+               send_size += wr->wr.sg_list[i].length;
 
        is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET;
        is_grh = mlx4_ib_ah_grh_present(ah);
@@ -2197,7 +2294,10 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                } else  {
                        err = ib_get_cached_gid(ib_dev,
                                                be32_to_cpu(ah->av.ib.port_pd) >> 24,
-                                               ah->av.ib.gid_index, &sgid);
+                                               ah->av.ib.gid_index, &sgid,
+                                               NULL);
+                       if (!err && !memcmp(&sgid, &zgid, sizeof(sgid)))
+                               err = -ENOENT;
                        if (err)
                                return err;
                }
@@ -2239,7 +2339,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                        ib_get_cached_gid(ib_dev,
                                          be32_to_cpu(ah->av.ib.port_pd) >> 24,
                                          ah->av.ib.gid_index,
-                                         &sqp->ud_header.grh.source_gid);
+                                         &sqp->ud_header.grh.source_gid, NULL);
                }
                memcpy(sqp->ud_header.grh.destination_gid.raw,
                       ah->av.ib.dgid, 16);
@@ -2257,7 +2357,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                mlx->rlid = sqp->ud_header.lrh.destination_lid;
        }
 
-       switch (wr->opcode) {
+       switch (wr->wr.opcode) {
        case IB_WR_SEND:
                sqp->ud_header.bth.opcode        = IB_OPCODE_UD_SEND_ONLY;
                sqp->ud_header.immediate_present = 0;
@@ -2265,7 +2365,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        case IB_WR_SEND_WITH_IMM:
                sqp->ud_header.bth.opcode        = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
                sqp->ud_header.immediate_present = 1;
-               sqp->ud_header.immediate_data    = wr->ex.imm_data;
+               sqp->ud_header.immediate_data    = wr->wr.ex.imm_data;
                break;
        default:
                return -EINVAL;
@@ -2308,16 +2408,16 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
                        sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
        }
-       sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
+       sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
        if (!sqp->qp.ibqp.qp_num)
                ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
        else
-               ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->wr.ud.pkey_index, &pkey);
+               ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->pkey_index, &pkey);
        sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
-       sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
        sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
-       sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ?
-                                              sqp->qkey : wr->wr.ud.remote_qkey);
+       sqp->ud_header.deth.qkey = cpu_to_be32(wr->remote_qkey & 0x80000000 ?
+                                              sqp->qkey : wr->remote_qkey);
        sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num);
 
        header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf);
@@ -2405,43 +2505,39 @@ static __be32 convert_access(int acc)
                cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_READ);
 }
 
-static void set_fmr_seg(struct mlx4_wqe_fmr_seg *fseg, struct ib_send_wr *wr)
+static void set_reg_seg(struct mlx4_wqe_fmr_seg *fseg,
+                       struct ib_reg_wr *wr)
 {
-       struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
-       int i;
-
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; ++i)
-               mfrpl->mapped_page_list[i] =
-                       cpu_to_be64(wr->wr.fast_reg.page_list->page_list[i] |
-                                   MLX4_MTT_FLAG_PRESENT);
+       struct mlx4_ib_mr *mr = to_mmr(wr->mr);
 
-       fseg->flags             = convert_access(wr->wr.fast_reg.access_flags);
-       fseg->mem_key           = cpu_to_be32(wr->wr.fast_reg.rkey);
-       fseg->buf_list          = cpu_to_be64(mfrpl->map);
-       fseg->start_addr        = cpu_to_be64(wr->wr.fast_reg.iova_start);
-       fseg->reg_len           = cpu_to_be64(wr->wr.fast_reg.length);
+       fseg->flags             = convert_access(wr->access);
+       fseg->mem_key           = cpu_to_be32(wr->key);
+       fseg->buf_list          = cpu_to_be64(mr->page_map);
+       fseg->start_addr        = cpu_to_be64(mr->ibmr.iova);
+       fseg->reg_len           = cpu_to_be64(mr->ibmr.length);
        fseg->offset            = 0; /* XXX -- is this just for ZBVA? */
-       fseg->page_size         = cpu_to_be32(wr->wr.fast_reg.page_shift);
+       fseg->page_size         = cpu_to_be32(ilog2(mr->ibmr.page_size));
        fseg->reserved[0]       = 0;
        fseg->reserved[1]       = 0;
 }
 
-static void set_bind_seg(struct mlx4_wqe_bind_seg *bseg, struct ib_send_wr *wr)
+static void set_bind_seg(struct mlx4_wqe_bind_seg *bseg,
+               struct ib_bind_mw_wr *wr)
 {
        bseg->flags1 =
-               convert_access(wr->wr.bind_mw.bind_info.mw_access_flags) &
+               convert_access(wr->bind_info.mw_access_flags) &
                cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_READ  |
                            MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_WRITE |
                            MLX4_WQE_FMR_AND_BIND_PERM_ATOMIC);
        bseg->flags2 = 0;
-       if (wr->wr.bind_mw.mw->type == IB_MW_TYPE_2)
+       if (wr->mw->type == IB_MW_TYPE_2)
                bseg->flags2 |= cpu_to_be32(MLX4_WQE_BIND_TYPE_2);
-       if (wr->wr.bind_mw.bind_info.mw_access_flags & IB_ZERO_BASED)
+       if (wr->bind_info.mw_access_flags & IB_ZERO_BASED)
                bseg->flags2 |= cpu_to_be32(MLX4_WQE_BIND_ZERO_BASED);
-       bseg->new_rkey = cpu_to_be32(wr->wr.bind_mw.rkey);
-       bseg->lkey = cpu_to_be32(wr->wr.bind_mw.bind_info.mr->lkey);
-       bseg->addr = cpu_to_be64(wr->wr.bind_mw.bind_info.addr);
-       bseg->length = cpu_to_be64(wr->wr.bind_mw.bind_info.length);
+       bseg->new_rkey = cpu_to_be32(wr->rkey);
+       bseg->lkey = cpu_to_be32(wr->bind_info.mr->lkey);
+       bseg->addr = cpu_to_be64(wr->bind_info.addr);
+       bseg->length = cpu_to_be64(wr->bind_info.length);
 }
 
 static void set_local_inv_seg(struct mlx4_wqe_local_inval_seg *iseg, u32 rkey)
@@ -2458,46 +2554,47 @@ static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
        rseg->reserved = 0;
 }
 
-static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg,
+               struct ib_atomic_wr *wr)
 {
-       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
-       } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+       if (wr->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->swap);
+               aseg->compare  = cpu_to_be64(wr->compare_add);
+       } else if (wr->wr.opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
+               aseg->swap_add = cpu_to_be64(wr->compare_add);
+               aseg->compare  = cpu_to_be64(wr->compare_add_mask);
        } else {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->swap_add = cpu_to_be64(wr->compare_add);
                aseg->compare  = 0;
        }
 
 }
 
 static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg,
-                                 struct ib_send_wr *wr)
+                                 struct ib_atomic_wr *wr)
 {
-       aseg->swap_add          = cpu_to_be64(wr->wr.atomic.swap);
-       aseg->swap_add_mask     = cpu_to_be64(wr->wr.atomic.swap_mask);
-       aseg->compare           = cpu_to_be64(wr->wr.atomic.compare_add);
-       aseg->compare_mask      = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+       aseg->swap_add          = cpu_to_be64(wr->swap);
+       aseg->swap_add_mask     = cpu_to_be64(wr->swap_mask);
+       aseg->compare           = cpu_to_be64(wr->compare_add);
+       aseg->compare_mask      = cpu_to_be64(wr->compare_add_mask);
 }
 
 static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
-                            struct ib_send_wr *wr)
+                            struct ib_ud_wr *wr)
 {
-       memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
-       dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
-       dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
-       dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan;
-       memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6);
+       memcpy(dseg->av, &to_mah(wr->ah)->av, sizeof (struct mlx4_av));
+       dseg->dqpn = cpu_to_be32(wr->remote_qpn);
+       dseg->qkey = cpu_to_be32(wr->remote_qkey);
+       dseg->vlan = to_mah(wr->ah)->av.eth.vlan;
+       memcpy(dseg->mac, to_mah(wr->ah)->av.eth.mac, 6);
 }
 
 static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev,
                                    struct mlx4_wqe_datagram_seg *dseg,
-                                   struct ib_send_wr *wr,
+                                   struct ib_ud_wr *wr,
                                    enum mlx4_ib_qp_type qpt)
 {
-       union mlx4_ext_av *av = &to_mah(wr->wr.ud.ah)->av;
+       union mlx4_ext_av *av = &to_mah(wr->ah)->av;
        struct mlx4_av sqp_av = {0};
        int port = *((u8 *) &av->ib.port_pd) & 0x3;
 
@@ -2516,18 +2613,18 @@ static void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev,
        dseg->qkey = cpu_to_be32(IB_QP_SET_QKEY);
 }
 
-static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_seg_len)
+static void build_tunnel_header(struct ib_ud_wr *wr, void *wqe, unsigned *mlx_seg_len)
 {
        struct mlx4_wqe_inline_seg *inl = wqe;
        struct mlx4_ib_tunnel_header hdr;
-       struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       struct mlx4_ib_ah *ah = to_mah(wr->ah);
        int spc;
        int i;
 
        memcpy(&hdr.av, &ah->av, sizeof hdr.av);
-       hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
-       hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index);
-       hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       hdr.remote_qpn = cpu_to_be32(wr->remote_qpn);
+       hdr.pkey_index = cpu_to_be16(wr->pkey_index);
+       hdr.qkey = cpu_to_be32(wr->remote_qkey);
        memcpy(hdr.mac, ah->av.eth.mac, 6);
        hdr.vlan = ah->av.eth.vlan;
 
@@ -2599,22 +2696,22 @@ static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
        dseg->addr       = cpu_to_be64(sg->addr);
 }
 
-static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr,
+static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_ud_wr *wr,
                         struct mlx4_ib_qp *qp, unsigned *lso_seg_len,
                         __be32 *lso_hdr_sz, __be32 *blh)
 {
-       unsigned halign = ALIGN(sizeof *wqe + wr->wr.ud.hlen, 16);
+       unsigned halign = ALIGN(sizeof *wqe + wr->hlen, 16);
 
        if (unlikely(halign > MLX4_IB_CACHE_LINE_SIZE))
                *blh = cpu_to_be32(1 << 6);
 
        if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) &&
-                    wr->num_sge > qp->sq.max_gs - (halign >> 4)))
+                    wr->wr.num_sge > qp->sq.max_gs - (halign >> 4)))
                return -EINVAL;
 
-       memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen);
+       memcpy(wqe->header, wr->header, wr->hlen);
 
-       *lso_hdr_sz  = cpu_to_be32(wr->wr.ud.mss << 16 | wr->wr.ud.hlen);
+       *lso_hdr_sz  = cpu_to_be32(wr->mss << 16 | wr->hlen);
        *lso_seg_len = halign;
        return 0;
 }
@@ -2713,11 +2810,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
                        case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD:
-                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
+                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+                                             atomic_wr(wr)->rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 
-                               set_atomic_seg(wqe, wr);
+                               set_atomic_seg(wqe, atomic_wr(wr));
                                wqe  += sizeof (struct mlx4_wqe_atomic_seg);
 
                                size += (sizeof (struct mlx4_wqe_raddr_seg) +
@@ -2726,11 +2823,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                break;
 
                        case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
-                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
+                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+                                             atomic_wr(wr)->rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 
-                               set_masked_atomic_seg(wqe, wr);
+                               set_masked_atomic_seg(wqe, atomic_wr(wr));
                                wqe  += sizeof (struct mlx4_wqe_masked_atomic_seg);
 
                                size += (sizeof (struct mlx4_wqe_raddr_seg) +
@@ -2741,8 +2838,8 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                wqe  += sizeof (struct mlx4_wqe_raddr_seg);
                                size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
                                break;
@@ -2755,18 +2852,18 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                size += sizeof (struct mlx4_wqe_local_inval_seg) / 16;
                                break;
 
-                       case IB_WR_FAST_REG_MR:
+                       case IB_WR_REG_MR:
                                ctrl->srcrb_flags |=
                                        cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
-                               set_fmr_seg(wqe, wr);
-                               wqe  += sizeof (struct mlx4_wqe_fmr_seg);
-                               size += sizeof (struct mlx4_wqe_fmr_seg) / 16;
+                               set_reg_seg(wqe, reg_wr(wr));
+                               wqe  += sizeof(struct mlx4_wqe_fmr_seg);
+                               size += sizeof(struct mlx4_wqe_fmr_seg) / 16;
                                break;
 
                        case IB_WR_BIND_MW:
                                ctrl->srcrb_flags |=
                                        cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
-                               set_bind_seg(wqe, wr);
+                               set_bind_seg(wqe, bind_mw_wr(wr));
                                wqe  += sizeof(struct mlx4_wqe_bind_seg);
                                size += sizeof(struct mlx4_wqe_bind_seg) / 16;
                                break;
@@ -2777,7 +2874,8 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case MLX4_IB_QPT_TUN_SMI_OWNER:
-                       err =  build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen);
+                       err =  build_sriov_qp0_header(to_msqp(qp), ud_wr(wr),
+                                       ctrl, &seglen);
                        if (unlikely(err)) {
                                *bad_wr = wr;
                                goto out;
@@ -2788,19 +2886,20 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                case MLX4_IB_QPT_TUN_SMI:
                case MLX4_IB_QPT_TUN_GSI:
                        /* this is a UD qp used in MAD responses to slaves. */
-                       set_datagram_seg(wqe, wr);
+                       set_datagram_seg(wqe, ud_wr(wr));
                        /* set the forced-loopback bit in the data seg av */
                        *(__be32 *) wqe |= cpu_to_be32(0x80000000);
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
                        break;
                case MLX4_IB_QPT_UD:
-                       set_datagram_seg(wqe, wr);
+                       set_datagram_seg(wqe, ud_wr(wr));
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
 
                        if (wr->opcode == IB_WR_LSO) {
-                               err = build_lso_seg(wqe, wr, qp, &seglen, &lso_hdr_sz, &blh);
+                               err = build_lso_seg(wqe, ud_wr(wr), qp, &seglen,
+                                               &lso_hdr_sz, &blh);
                                if (unlikely(err)) {
                                        *bad_wr = wr;
                                        goto out;
@@ -2812,7 +2911,8 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case MLX4_IB_QPT_PROXY_SMI_OWNER:
-                       err = build_sriov_qp0_header(to_msqp(qp), wr, ctrl, &seglen);
+                       err = build_sriov_qp0_header(to_msqp(qp), ud_wr(wr),
+                                       ctrl, &seglen);
                        if (unlikely(err)) {
                                *bad_wr = wr;
                                goto out;
@@ -2823,7 +2923,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        add_zero_len_inline(wqe);
                        wqe += 16;
                        size++;
-                       build_tunnel_header(wr, wqe, &seglen);
+                       build_tunnel_header(ud_wr(wr), wqe, &seglen);
                        wqe  += seglen;
                        size += seglen / 16;
                        break;
@@ -2833,18 +2933,20 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                         * In this case we first add a UD segment targeting
                         * the tunnel qp, and then add a header with address
                         * information */
-                       set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe, wr,
+                       set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe,
+                                               ud_wr(wr),
                                                qp->mlx4_ib_qp_type);
                        wqe  += sizeof (struct mlx4_wqe_datagram_seg);
                        size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
-                       build_tunnel_header(wr, wqe, &seglen);
+                       build_tunnel_header(ud_wr(wr), wqe, &seglen);
                        wqe  += seglen;
                        size += seglen / 16;
                        break;
 
                case MLX4_IB_QPT_SMI:
                case MLX4_IB_QPT_GSI:
-                       err = build_mlx_header(to_msqp(qp), wr, ctrl, &seglen);
+                       err = build_mlx_header(to_msqp(qp), ud_wr(wr), ctrl,
+                                       &seglen);
                        if (unlikely(err)) {
                                *bad_wr = wr;
                                goto out;
index 2d0dbbf38ceb9f6277bc9c86e726b97a6e33f17d..3dfd287256d628892823173a4794620b4e22849e 100644 (file)
@@ -109,8 +109,8 @@ static enum ib_wc_opcode get_umr_comp(struct mlx5_ib_wq *wq, int idx)
        case IB_WR_LOCAL_INV:
                return IB_WC_LOCAL_INV;
 
-       case IB_WR_FAST_REG_MR:
-               return IB_WC_FAST_REG_MR;
+       case IB_WR_REG_MR:
+               return IB_WC_REG_MR;
 
        default:
                pr_warn("unknown completion status\n");
index f1ccd40beae9eb2b7a8e6aaad7ef1a98ab8a0a81..7e97cb55a6bfa9517a726b9be897d17563272a5d 100644 (file)
@@ -30,7 +30,7 @@
  * SOFTWARE.
  */
 
-#include <asm-generic/kmap_types.h>
+#include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
@@ -1425,8 +1425,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
        dev->ib_dev.detach_mcast        = mlx5_ib_mcg_detach;
        dev->ib_dev.process_mad         = mlx5_ib_process_mad;
        dev->ib_dev.alloc_mr            = mlx5_ib_alloc_mr;
-       dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list;
-       dev->ib_dev.free_fast_reg_page_list  = mlx5_ib_free_fast_reg_page_list;
+       dev->ib_dev.map_mr_sg           = mlx5_ib_map_mr_sg;
        dev->ib_dev.check_mr_status     = mlx5_ib_check_mr_status;
        dev->ib_dev.get_port_immutable  = mlx5_port_immutable;
 
index 22123b79d550d6a7e0474501592f36dc6f0b632e..633347260b79454ba10da9de498bc9d68d5a6f9f 100644 (file)
@@ -245,6 +245,7 @@ enum mlx5_ib_qp_flags {
 };
 
 struct mlx5_umr_wr {
+       struct ib_send_wr               wr;
        union {
                u64                     virt_addr;
                u64                     offset;
@@ -257,6 +258,11 @@ struct mlx5_umr_wr {
        u32                             mkey;
 };
 
+static inline struct mlx5_umr_wr *umr_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct mlx5_umr_wr, wr);
+}
+
 struct mlx5_shared_mr_info {
        int mr_id;
        struct ib_umem          *umem;
@@ -313,6 +319,11 @@ enum mlx5_ib_mtt_access_flags {
 
 struct mlx5_ib_mr {
        struct ib_mr            ibmr;
+       void                    *descs;
+       dma_addr_t              desc_map;
+       int                     ndescs;
+       int                     max_descs;
+       int                     desc_size;
        struct mlx5_core_mr     mmr;
        struct ib_umem         *umem;
        struct mlx5_shared_mr_info      *smr_info;
@@ -324,12 +335,7 @@ struct mlx5_ib_mr {
        struct mlx5_create_mkey_mbox_out out;
        struct mlx5_core_sig_ctx    *sig;
        int                     live;
-};
-
-struct mlx5_ib_fast_reg_page_list {
-       struct ib_fast_reg_page_list    ibfrpl;
-       __be64                         *mapped_page_list;
-       dma_addr_t                      map;
+       void                    *descs_alloc;
 };
 
 struct mlx5_ib_umr_context {
@@ -358,20 +364,6 @@ enum {
        MLX5_FMR_BUSY,
 };
 
-struct mlx5_ib_fmr {
-       struct ib_fmr                   ibfmr;
-       struct mlx5_core_mr             mr;
-       int                             access_flags;
-       int                             state;
-       /* protect fmr state
-        */
-       spinlock_t                      lock;
-       u64                             wrid;
-       struct ib_send_wr               wr[2];
-       u8                              page_shift;
-       struct ib_fast_reg_page_list    page_list;
-};
-
 struct mlx5_cache_ent {
        struct list_head        head;
        /* sync access to the cahce entry
@@ -456,11 +448,6 @@ static inline struct mlx5_ib_dev *to_mdev(struct ib_device *ibdev)
        return container_of(ibdev, struct mlx5_ib_dev, ib_dev);
 }
 
-static inline struct mlx5_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
-{
-       return container_of(ibfmr, struct mlx5_ib_fmr, ibfmr);
-}
-
 static inline struct mlx5_ib_cq *to_mcq(struct ib_cq *ibcq)
 {
        return container_of(ibcq, struct mlx5_ib_cq, ibcq);
@@ -501,11 +488,6 @@ static inline struct mlx5_ib_mr *to_mmr(struct ib_mr *ibmr)
        return container_of(ibmr, struct mlx5_ib_mr, ibmr);
 }
 
-static inline struct mlx5_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl)
-{
-       return container_of(ibfrpl, struct mlx5_ib_fast_reg_page_list, ibfrpl);
-}
-
 struct mlx5_ib_ah {
        struct ib_ah            ibah;
        struct mlx5_av          av;
@@ -573,15 +555,9 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr);
 struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd,
                               enum ib_mr_type mr_type,
                               u32 max_num_sg);
-struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
-                                                              int page_list_len);
-void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list);
-struct ib_fmr *mlx5_ib_fmr_alloc(struct ib_pd *pd, int acc,
-                                struct ib_fmr_attr *fmr_attr);
-int mlx5_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
-                     int npages, u64 iova);
-int mlx5_ib_unmap_fmr(struct list_head *fmr_list);
-int mlx5_ib_fmr_dealloc(struct ib_fmr *ibfmr);
+int mlx5_ib_map_mr_sg(struct ib_mr *ibmr,
+                     struct scatterlist *sg,
+                     int sg_nents);
 int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
                        const struct ib_wc *in_wc, const struct ib_grh *in_grh,
                        const struct ib_mad_hdr *in, size_t in_mad_size,
index 54a15b5d336d00043643c09a99f05b89df2861bd..ec8993a7b3beea5a91370c1f66979dae583f49d4 100644 (file)
@@ -687,7 +687,7 @@ static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
                             int access_flags)
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
-       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
+       struct mlx5_umr_wr *umrwr = umr_wr(wr);
 
        sg->addr = dma;
        sg->length = ALIGN(sizeof(u64) * n, 64);
@@ -715,7 +715,7 @@ static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
 static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev,
                               struct ib_send_wr *wr, u32 key)
 {
-       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
+       struct mlx5_umr_wr *umrwr = umr_wr(wr);
 
        wr->send_flags = MLX5_IB_SEND_UMR_UNREG | MLX5_IB_SEND_UMR_FAIL_IF_FREE;
        wr->opcode = MLX5_IB_WR_UMR;
@@ -752,7 +752,8 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        struct device *ddev = dev->ib_dev.dma_device;
        struct umr_common *umrc = &dev->umrc;
        struct mlx5_ib_umr_context umr_context;
-       struct ib_send_wr wr, *bad;
+       struct mlx5_umr_wr umrwr;
+       struct ib_send_wr *bad;
        struct mlx5_ib_mr *mr;
        struct ib_sge sg;
        int size;
@@ -798,14 +799,14 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
                goto free_pas;
        }
 
-       memset(&wr, 0, sizeof(wr));
-       wr.wr_id = (u64)(unsigned long)&umr_context;
-       prep_umr_reg_wqe(pd, &wr, &sg, dma, npages, mr->mmr.key, page_shift,
-                        virt_addr, len, access_flags);
+       memset(&umrwr, 0, sizeof(umrwr));
+       umrwr.wr.wr_id = (u64)(unsigned long)&umr_context;
+       prep_umr_reg_wqe(pd, &umrwr.wr, &sg, dma, npages, mr->mmr.key,
+                        page_shift, virt_addr, len, access_flags);
 
        mlx5_ib_init_umr_context(&umr_context);
        down(&umrc->sem);
-       err = ib_post_send(umrc->qp, &wr, &bad);
+       err = ib_post_send(umrc->qp, &umrwr.wr, &bad);
        if (err) {
                mlx5_ib_warn(dev, "post send failed, err %d\n", err);
                goto unmap_dma;
@@ -851,8 +852,8 @@ int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index, int npages,
        int size;
        __be64 *pas;
        dma_addr_t dma;
-       struct ib_send_wr wr, *bad;
-       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr.wr.fast_reg;
+       struct ib_send_wr *bad;
+       struct mlx5_umr_wr wr;
        struct ib_sge sg;
        int err = 0;
        const int page_index_alignment = MLX5_UMR_MTT_ALIGNMENT / sizeof(u64);
@@ -917,26 +918,26 @@ int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index, int npages,
                dma_sync_single_for_device(ddev, dma, size, DMA_TO_DEVICE);
 
                memset(&wr, 0, sizeof(wr));
-               wr.wr_id = (u64)(unsigned long)&umr_context;
+               wr.wr.wr_id = (u64)(unsigned long)&umr_context;
 
                sg.addr = dma;
                sg.length = ALIGN(npages * sizeof(u64),
                                MLX5_UMR_MTT_ALIGNMENT);
                sg.lkey = dev->umrc.pd->local_dma_lkey;
 
-               wr.send_flags = MLX5_IB_SEND_UMR_FAIL_IF_FREE |
+               wr.wr.send_flags = MLX5_IB_SEND_UMR_FAIL_IF_FREE |
                                MLX5_IB_SEND_UMR_UPDATE_MTT;
-               wr.sg_list = &sg;
-               wr.num_sge = 1;
-               wr.opcode = MLX5_IB_WR_UMR;
-               umrwr->npages = sg.length / sizeof(u64);
-               umrwr->page_shift = PAGE_SHIFT;
-               umrwr->mkey = mr->mmr.key;
-               umrwr->target.offset = start_page_index;
+               wr.wr.sg_list = &sg;
+               wr.wr.num_sge = 1;
+               wr.wr.opcode = MLX5_IB_WR_UMR;
+               wr.npages = sg.length / sizeof(u64);
+               wr.page_shift = PAGE_SHIFT;
+               wr.mkey = mr->mmr.key;
+               wr.target.offset = start_page_index;
 
                mlx5_ib_init_umr_context(&umr_context);
                down(&umrc->sem);
-               err = ib_post_send(umrc->qp, &wr, &bad);
+               err = ib_post_send(umrc->qp, &wr.wr, &bad);
                if (err) {
                        mlx5_ib_err(dev, "UMR post send failed, err %d\n", err);
                } else {
@@ -1122,16 +1123,17 @@ static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
 {
        struct umr_common *umrc = &dev->umrc;
        struct mlx5_ib_umr_context umr_context;
-       struct ib_send_wr wr, *bad;
+       struct mlx5_umr_wr umrwr;
+       struct ib_send_wr *bad;
        int err;
 
-       memset(&wr, 0, sizeof(wr));
-       wr.wr_id = (u64)(unsigned long)&umr_context;
-       prep_umr_unreg_wqe(dev, &wr, mr->mmr.key);
+       memset(&umrwr.wr, 0, sizeof(umrwr));
+       umrwr.wr.wr_id = (u64)(unsigned long)&umr_context;
+       prep_umr_unreg_wqe(dev, &umrwr.wr, mr->mmr.key);
 
        mlx5_ib_init_umr_context(&umr_context);
        down(&umrc->sem);
-       err = ib_post_send(umrc->qp, &wr, &bad);
+       err = ib_post_send(umrc->qp, &umrwr.wr, &bad);
        if (err) {
                up(&umrc->sem);
                mlx5_ib_dbg(dev, "err %d\n", err);
@@ -1151,6 +1153,52 @@ error:
        return err;
 }
 
+static int
+mlx5_alloc_priv_descs(struct ib_device *device,
+                     struct mlx5_ib_mr *mr,
+                     int ndescs,
+                     int desc_size)
+{
+       int size = ndescs * desc_size;
+       int add_size;
+       int ret;
+
+       add_size = max_t(int, MLX5_UMR_ALIGN - ARCH_KMALLOC_MINALIGN, 0);
+
+       mr->descs_alloc = kzalloc(size + add_size, GFP_KERNEL);
+       if (!mr->descs_alloc)
+               return -ENOMEM;
+
+       mr->descs = PTR_ALIGN(mr->descs_alloc, MLX5_UMR_ALIGN);
+
+       mr->desc_map = dma_map_single(device->dma_device, mr->descs,
+                                     size, DMA_TO_DEVICE);
+       if (dma_mapping_error(device->dma_device, mr->desc_map)) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(mr->descs_alloc);
+
+       return ret;
+}
+
+static void
+mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
+{
+       if (mr->descs) {
+               struct ib_device *device = mr->ibmr.device;
+               int size = mr->max_descs * mr->desc_size;
+
+               dma_unmap_single(device->dma_device, mr->desc_map,
+                                size, DMA_TO_DEVICE);
+               kfree(mr->descs_alloc);
+               mr->descs = NULL;
+       }
+}
+
 static int clean_mr(struct mlx5_ib_mr *mr)
 {
        struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
@@ -1170,6 +1218,8 @@ static int clean_mr(struct mlx5_ib_mr *mr)
                mr->sig = NULL;
        }
 
+       mlx5_free_priv_descs(mr);
+
        if (!umred) {
                err = destroy_mkey(dev, mr);
                if (err) {
@@ -1259,6 +1309,14 @@ struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd,
        if (mr_type == IB_MR_TYPE_MEM_REG) {
                access_mode = MLX5_ACCESS_MODE_MTT;
                in->seg.log2_page_size = PAGE_SHIFT;
+
+               err = mlx5_alloc_priv_descs(pd->device, mr,
+                                           ndescs, sizeof(u64));
+               if (err)
+                       goto err_free_in;
+
+               mr->desc_size = sizeof(u64);
+               mr->max_descs = ndescs;
        } else if (mr_type == IB_MR_TYPE_SIGNATURE) {
                u32 psv_index[2];
 
@@ -1315,6 +1373,7 @@ err_destroy_psv:
                        mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
                                     mr->sig->psv_wire.psv_idx);
        }
+       mlx5_free_priv_descs(mr);
 err_free_sig:
        kfree(mr->sig);
 err_free_in:
@@ -1324,48 +1383,6 @@ err_free:
        return ERR_PTR(err);
 }
 
-struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
-                                                              int page_list_len)
-{
-       struct mlx5_ib_fast_reg_page_list *mfrpl;
-       int size = page_list_len * sizeof(u64);
-
-       mfrpl = kmalloc(sizeof(*mfrpl), GFP_KERNEL);
-       if (!mfrpl)
-               return ERR_PTR(-ENOMEM);
-
-       mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL);
-       if (!mfrpl->ibfrpl.page_list)
-               goto err_free;
-
-       mfrpl->mapped_page_list = dma_alloc_coherent(ibdev->dma_device,
-                                                    size, &mfrpl->map,
-                                                    GFP_KERNEL);
-       if (!mfrpl->mapped_page_list)
-               goto err_free;
-
-       WARN_ON(mfrpl->map & 0x3f);
-
-       return &mfrpl->ibfrpl;
-
-err_free:
-       kfree(mfrpl->ibfrpl.page_list);
-       kfree(mfrpl);
-       return ERR_PTR(-ENOMEM);
-}
-
-void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
-{
-       struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list);
-       struct mlx5_ib_dev *dev = to_mdev(page_list->device);
-       int size = page_list->max_page_list_len * sizeof(u64);
-
-       dma_free_coherent(&dev->mdev->pdev->dev, size, mfrpl->mapped_page_list,
-                         mfrpl->map);
-       kfree(mfrpl->ibfrpl.page_list);
-       kfree(mfrpl);
-}
-
 int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
                            struct ib_mr_status *mr_status)
 {
@@ -1406,3 +1423,39 @@ int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
 done:
        return ret;
 }
+
+static int mlx5_set_page(struct ib_mr *ibmr, u64 addr)
+{
+       struct mlx5_ib_mr *mr = to_mmr(ibmr);
+       __be64 *descs;
+
+       if (unlikely(mr->ndescs == mr->max_descs))
+               return -ENOMEM;
+
+       descs = mr->descs;
+       descs[mr->ndescs++] = cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
+
+       return 0;
+}
+
+int mlx5_ib_map_mr_sg(struct ib_mr *ibmr,
+                     struct scatterlist *sg,
+                     int sg_nents)
+{
+       struct mlx5_ib_mr *mr = to_mmr(ibmr);
+       int n;
+
+       mr->ndescs = 0;
+
+       ib_dma_sync_single_for_cpu(ibmr->device, mr->desc_map,
+                                  mr->desc_size * mr->max_descs,
+                                  DMA_TO_DEVICE);
+
+       n = ib_sg_to_pages(ibmr, sg, sg_nents, mlx5_set_page);
+
+       ib_dma_sync_single_for_device(ibmr->device, mr->desc_map,
+                                     mr->desc_size * mr->max_descs,
+                                     DMA_TO_DEVICE);
+
+       return n;
+}
index 6f521a3418e8e1c69b9cca74fc8443dd05e30dac..307bdbca8938e1d87493d7048b93126bd9261e26 100644 (file)
@@ -64,7 +64,7 @@ static const u32 mlx5_ib_opcode[] = {
        [IB_WR_ATOMIC_FETCH_AND_ADD]            = MLX5_OPCODE_ATOMIC_FA,
        [IB_WR_SEND_WITH_INV]                   = MLX5_OPCODE_SEND_INVAL,
        [IB_WR_LOCAL_INV]                       = MLX5_OPCODE_UMR,
-       [IB_WR_FAST_REG_MR]                     = MLX5_OPCODE_UMR,
+       [IB_WR_REG_MR]                          = MLX5_OPCODE_UMR,
        [IB_WR_MASKED_ATOMIC_CMP_AND_SWP]       = MLX5_OPCODE_ATOMIC_MASKED_CS,
        [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]     = MLX5_OPCODE_ATOMIC_MASKED_FA,
        [MLX5_IB_WR_UMR]                        = MLX5_OPCODE_UMR,
@@ -1838,9 +1838,9 @@ static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
 static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
                             struct ib_send_wr *wr)
 {
-       memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof(struct mlx5_av));
-       dseg->av.dqp_dct = cpu_to_be32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV);
-       dseg->av.key.qkey.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       memcpy(&dseg->av, &to_mah(ud_wr(wr)->ah)->av, sizeof(struct mlx5_av));
+       dseg->av.dqp_dct = cpu_to_be32(ud_wr(wr)->remote_qpn | MLX5_EXTENDED_UD_AV);
+       dseg->av.key.qkey.qkey = cpu_to_be32(ud_wr(wr)->remote_qkey);
 }
 
 static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
@@ -1896,22 +1896,24 @@ static __be64 sig_mkey_mask(void)
        return cpu_to_be64(result);
 }
 
-static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
-                                struct ib_send_wr *wr, int li)
+static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
+                               struct mlx5_ib_mr *mr)
 {
-       memset(umr, 0, sizeof(*umr));
-
-       if (li) {
-               umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
-               umr->flags = 1 << 7;
-               return;
-       }
+       int ndescs = mr->ndescs;
 
-       umr->flags = (1 << 5); /* fail if not free */
-       umr->klm_octowords = get_klm_octo(wr->wr.fast_reg.page_list_len);
+       memset(umr, 0, sizeof(*umr));
+       umr->flags = MLX5_UMR_CHECK_NOT_FREE;
+       umr->klm_octowords = get_klm_octo(ndescs);
        umr->mkey_mask = frwr_mkey_mask();
 }
 
+static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
+{
+       memset(umr, 0, sizeof(*umr));
+       umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
+       umr->flags = 1 << 7;
+}
+
 static __be64 get_umr_reg_mr_mask(void)
 {
        u64 result;
@@ -1952,7 +1954,7 @@ static __be64 get_umr_update_mtt_mask(void)
 static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
                                struct ib_send_wr *wr)
 {
-       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
+       struct mlx5_umr_wr *umrwr = umr_wr(wr);
 
        memset(umr, 0, sizeof(*umr));
 
@@ -1987,29 +1989,31 @@ static u8 get_umr_flags(int acc)
                MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN;
 }
 
-static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr,
-                            int li, int *writ)
+static void set_reg_mkey_seg(struct mlx5_mkey_seg *seg,
+                            struct mlx5_ib_mr *mr,
+                            u32 key, int access)
 {
-       memset(seg, 0, sizeof(*seg));
-       if (li) {
-               seg->status = MLX5_MKEY_STATUS_FREE;
-               return;
-       }
+       int ndescs = ALIGN(mr->ndescs, 8) >> 1;
 
-       seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags) |
-                    MLX5_ACCESS_MODE_MTT;
-       *writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE);
-       seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00);
+       memset(seg, 0, sizeof(*seg));
+       seg->flags = get_umr_flags(access) | MLX5_ACCESS_MODE_MTT;
+       seg->qpn_mkey7_0 = cpu_to_be32((key & 0xff) | 0xffffff00);
        seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
-       seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start);
-       seg->len = cpu_to_be64(wr->wr.fast_reg.length);
-       seg->xlt_oct_size = cpu_to_be32((wr->wr.fast_reg.page_list_len + 1) / 2);
-       seg->log2_page_size = wr->wr.fast_reg.page_shift;
+       seg->start_addr = cpu_to_be64(mr->ibmr.iova);
+       seg->len = cpu_to_be64(mr->ibmr.length);
+       seg->xlt_oct_size = cpu_to_be32(ndescs);
+       seg->log2_page_size = ilog2(mr->ibmr.page_size);
+}
+
+static void set_linv_mkey_seg(struct mlx5_mkey_seg *seg)
+{
+       memset(seg, 0, sizeof(*seg));
+       seg->status = MLX5_MKEY_STATUS_FREE;
 }
 
 static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr)
 {
-       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
+       struct mlx5_umr_wr *umrwr = umr_wr(wr);
 
        memset(seg, 0, sizeof(*seg));
        if (wr->send_flags & MLX5_IB_SEND_UMR_UNREG) {
@@ -2028,21 +2032,14 @@ static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *w
                                       mlx5_mkey_variant(umrwr->mkey));
 }
 
-static void set_frwr_pages(struct mlx5_wqe_data_seg *dseg,
-                          struct ib_send_wr *wr,
-                          struct mlx5_core_dev *mdev,
-                          struct mlx5_ib_pd *pd,
-                          int writ)
+static void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg,
+                            struct mlx5_ib_mr *mr,
+                            struct mlx5_ib_pd *pd)
 {
-       struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
-       u64 *page_list = wr->wr.fast_reg.page_list->page_list;
-       u64 perm = MLX5_EN_RD | (writ ? MLX5_EN_WR : 0);
-       int i;
+       int bcount = mr->desc_size * mr->ndescs;
 
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++)
-               mfrpl->mapped_page_list[i] = cpu_to_be64(page_list[i] | perm);
-       dseg->addr = cpu_to_be64(mfrpl->map);
-       dseg->byte_count = cpu_to_be32(ALIGN(sizeof(u64) * wr->wr.fast_reg.page_list_len, 64));
+       dseg->addr = cpu_to_be64(mr->desc_map);
+       dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64));
        dseg->lkey = cpu_to_be32(pd->ibpd.local_dma_lkey);
 }
 
@@ -2224,22 +2221,22 @@ static int mlx5_set_bsf(struct ib_mr *sig_mr,
        return 0;
 }
 
-static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
-                               void **seg, int *size)
+static int set_sig_data_segment(struct ib_sig_handover_wr *wr,
+                               struct mlx5_ib_qp *qp, void **seg, int *size)
 {
-       struct ib_sig_attrs *sig_attrs = wr->wr.sig_handover.sig_attrs;
-       struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr;
+       struct ib_sig_attrs *sig_attrs = wr->sig_attrs;
+       struct ib_mr *sig_mr = wr->sig_mr;
        struct mlx5_bsf *bsf;
-       u32 data_len = wr->sg_list->length;
-       u32 data_key = wr->sg_list->lkey;
-       u64 data_va = wr->sg_list->addr;
+       u32 data_len = wr->wr.sg_list->length;
+       u32 data_key = wr->wr.sg_list->lkey;
+       u64 data_va = wr->wr.sg_list->addr;
        int ret;
        int wqe_size;
 
-       if (!wr->wr.sig_handover.prot ||
-           (data_key == wr->wr.sig_handover.prot->lkey &&
-            data_va == wr->wr.sig_handover.prot->addr &&
-            data_len == wr->wr.sig_handover.prot->length)) {
+       if (!wr->prot ||
+           (data_key == wr->prot->lkey &&
+            data_va == wr->prot->addr &&
+            data_len == wr->prot->length)) {
                /**
                 * Source domain doesn't contain signature information
                 * or data and protection are interleaved in memory.
@@ -2273,8 +2270,8 @@ static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
                struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
                struct mlx5_stride_block_entry *data_sentry;
                struct mlx5_stride_block_entry *prot_sentry;
-               u32 prot_key = wr->wr.sig_handover.prot->lkey;
-               u64 prot_va = wr->wr.sig_handover.prot->addr;
+               u32 prot_key = wr->prot->lkey;
+               u64 prot_va = wr->prot->addr;
                u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
                int prot_size;
 
@@ -2326,16 +2323,16 @@ static int set_sig_data_segment(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
 }
 
 static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
-                                struct ib_send_wr *wr, u32 nelements,
+                                struct ib_sig_handover_wr *wr, u32 nelements,
                                 u32 length, u32 pdn)
 {
-       struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr;
+       struct ib_mr *sig_mr = wr->sig_mr;
        u32 sig_key = sig_mr->rkey;
        u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
 
        memset(seg, 0, sizeof(*seg));
 
-       seg->flags = get_umr_flags(wr->wr.sig_handover.access_flags) |
+       seg->flags = get_umr_flags(wr->access_flags) |
                                   MLX5_ACCESS_MODE_KLM;
        seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
        seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
@@ -2346,7 +2343,7 @@ static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
 }
 
 static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
-                               struct ib_send_wr *wr, u32 nelements)
+                               u32 nelements)
 {
        memset(umr, 0, sizeof(*umr));
 
@@ -2357,37 +2354,37 @@ static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
 }
 
 
-static int set_sig_umr_wr(struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
+static int set_sig_umr_wr(struct ib_send_wr *send_wr, struct mlx5_ib_qp *qp,
                          void **seg, int *size)
 {
-       struct mlx5_ib_mr *sig_mr = to_mmr(wr->wr.sig_handover.sig_mr);
+       struct ib_sig_handover_wr *wr = sig_handover_wr(send_wr);
+       struct mlx5_ib_mr *sig_mr = to_mmr(wr->sig_mr);
        u32 pdn = get_pd(qp)->pdn;
        u32 klm_oct_size;
        int region_len, ret;
 
-       if (unlikely(wr->num_sge != 1) ||
-           unlikely(wr->wr.sig_handover.access_flags &
-                    IB_ACCESS_REMOTE_ATOMIC) ||
+       if (unlikely(wr->wr.num_sge != 1) ||
+           unlikely(wr->access_flags & IB_ACCESS_REMOTE_ATOMIC) ||
            unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) ||
            unlikely(!sig_mr->sig->sig_status_checked))
                return -EINVAL;
 
        /* length of the protected region, data + protection */
-       region_len = wr->sg_list->length;
-       if (wr->wr.sig_handover.prot &&
-           (wr->wr.sig_handover.prot->lkey != wr->sg_list->lkey  ||
-            wr->wr.sig_handover.prot->addr != wr->sg_list->addr  ||
-            wr->wr.sig_handover.prot->length != wr->sg_list->length))
-               region_len += wr->wr.sig_handover.prot->length;
+       region_len = wr->wr.sg_list->length;
+       if (wr->prot &&
+           (wr->prot->lkey != wr->wr.sg_list->lkey  ||
+            wr->prot->addr != wr->wr.sg_list->addr  ||
+            wr->prot->length != wr->wr.sg_list->length))
+               region_len += wr->prot->length;
 
        /**
         * KLM octoword size - if protection was provided
         * then we use strided block format (3 octowords),
         * else we use single KLM (1 octoword)
         **/
-       klm_oct_size = wr->wr.sig_handover.prot ? 3 : 1;
+       klm_oct_size = wr->prot ? 3 : 1;
 
-       set_sig_umr_segment(*seg, wr, klm_oct_size);
+       set_sig_umr_segment(*seg, klm_oct_size);
        *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
        *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
        if (unlikely((*seg == qp->sq.qend)))
@@ -2433,38 +2430,52 @@ static int set_psv_wr(struct ib_sig_domain *domain,
        return 0;
 }
 
-static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size,
-                         struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp)
+static int set_reg_wr(struct mlx5_ib_qp *qp,
+                     struct ib_reg_wr *wr,
+                     void **seg, int *size)
 {
-       int writ = 0;
-       int li;
+       struct mlx5_ib_mr *mr = to_mmr(wr->mr);
+       struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
 
-       li = wr->opcode == IB_WR_LOCAL_INV ? 1 : 0;
-       if (unlikely(wr->send_flags & IB_SEND_INLINE))
+       if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
+               mlx5_ib_warn(to_mdev(qp->ibqp.device),
+                            "Invalid IB_SEND_INLINE send flag\n");
                return -EINVAL;
+       }
 
-       set_frwr_umr_segment(*seg, wr, li);
+       set_reg_umr_seg(*seg, mr);
        *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
        *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
        if (unlikely((*seg == qp->sq.qend)))
                *seg = mlx5_get_send_wqe(qp, 0);
-       set_mkey_segment(*seg, wr, li, &writ);
+
+       set_reg_mkey_seg(*seg, mr, wr->key, wr->access);
        *seg += sizeof(struct mlx5_mkey_seg);
        *size += sizeof(struct mlx5_mkey_seg) / 16;
        if (unlikely((*seg == qp->sq.qend)))
                *seg = mlx5_get_send_wqe(qp, 0);
-       if (!li) {
-               if (unlikely(wr->wr.fast_reg.page_list_len >
-                            wr->wr.fast_reg.page_list->max_page_list_len))
-                       return  -ENOMEM;
 
-               set_frwr_pages(*seg, wr, mdev, pd, writ);
-               *seg += sizeof(struct mlx5_wqe_data_seg);
-               *size += (sizeof(struct mlx5_wqe_data_seg) / 16);
-       }
+       set_reg_data_seg(*seg, mr, pd);
+       *seg += sizeof(struct mlx5_wqe_data_seg);
+       *size += (sizeof(struct mlx5_wqe_data_seg) / 16);
+
        return 0;
 }
 
+static void set_linv_wr(struct mlx5_ib_qp *qp, void **seg, int *size)
+{
+       set_linv_umr_seg(*seg);
+       *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+       *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+       if (unlikely((*seg == qp->sq.qend)))
+               *seg = mlx5_get_send_wqe(qp, 0);
+       set_linv_mkey_seg(*seg);
+       *seg += sizeof(struct mlx5_mkey_seg);
+       *size += sizeof(struct mlx5_mkey_seg) / 16;
+       if (unlikely((*seg == qp->sq.qend)))
+               *seg = mlx5_get_send_wqe(qp, 0);
+}
+
 static void dump_wqe(struct mlx5_ib_qp *qp, int idx, int size_16)
 {
        __be32 *p = NULL;
@@ -2578,7 +2589,6 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 {
        struct mlx5_wqe_ctrl_seg *ctrl = NULL;  /* compiler warning */
        struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
-       struct mlx5_core_dev *mdev = dev->mdev;
        struct mlx5_ib_qp *qp = to_mqp(ibqp);
        struct mlx5_ib_mr *mr;
        struct mlx5_wqe_data_seg *dpseg;
@@ -2627,7 +2637,6 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                switch (ibqp->qp_type) {
                case IB_QPT_XRC_INI:
                        xrc = seg;
-                       xrc->xrc_srqn = htonl(wr->xrc_remote_srq_num);
                        seg += sizeof(*xrc);
                        size += sizeof(*xrc) / 16;
                        /* fall through */
@@ -2636,8 +2645,8 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(seg, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(seg, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                seg += sizeof(struct mlx5_wqe_raddr_seg);
                                size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
                                break;
@@ -2654,22 +2663,16 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
                                qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
                                ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
-                               err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
-                               if (err) {
-                                       mlx5_ib_warn(dev, "\n");
-                                       *bad_wr = wr;
-                                       goto out;
-                               }
+                               set_linv_wr(qp, &seg, &size);
                                num_sge = 0;
                                break;
 
-                       case IB_WR_FAST_REG_MR:
+                       case IB_WR_REG_MR:
                                next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
-                               qp->sq.wr_data[idx] = IB_WR_FAST_REG_MR;
-                               ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
-                               err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
+                               qp->sq.wr_data[idx] = IB_WR_REG_MR;
+                               ctrl->imm = cpu_to_be32(reg_wr(wr)->key);
+                               err = set_reg_wr(qp, reg_wr(wr), &seg, &size);
                                if (err) {
-                                       mlx5_ib_warn(dev, "\n");
                                        *bad_wr = wr;
                                        goto out;
                                }
@@ -2678,7 +2681,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
                        case IB_WR_REG_SIG_MR:
                                qp->sq.wr_data[idx] = IB_WR_REG_SIG_MR;
-                               mr = to_mmr(wr->wr.sig_handover.sig_mr);
+                               mr = to_mmr(sig_handover_wr(wr)->sig_mr);
 
                                ctrl->imm = cpu_to_be32(mr->ibmr.rkey);
                                err = set_sig_umr_wr(wr, qp, &seg, &size);
@@ -2706,7 +2709,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                        goto out;
                                }
 
-                               err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->mem,
+                               err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->mem,
                                                 mr->sig->psv_memory.psv_idx, &seg,
                                                 &size);
                                if (err) {
@@ -2728,7 +2731,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                }
 
                                next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
-                               err = set_psv_wr(&wr->wr.sig_handover.sig_attrs->wire,
+                               err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->wire,
                                                 mr->sig->psv_wire.psv_idx, &seg,
                                                 &size);
                                if (err) {
@@ -2752,8 +2755,8 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(seg, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(seg, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                seg  += sizeof(struct mlx5_wqe_raddr_seg);
                                size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
                                break;
@@ -2780,7 +2783,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                goto out;
                        }
                        qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
-                       ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
+                       ctrl->imm = cpu_to_be32(umr_wr(wr)->mkey);
                        set_reg_umr_segment(seg, wr);
                        seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
                        size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
index 32f6c63154541dec229ec8904d1438fddb88d14d..bcac294042f5e315e6324cbb0478f56d0524049c 100644 (file)
@@ -281,7 +281,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                ib_get_cached_gid(&dev->ib_dev,
                                  be32_to_cpu(ah->av->port_pd) >> 24,
                                  ah->av->gid_index % dev->limits.gid_table_len,
-                                 &header->grh.source_gid);
+                                 &header->grh.source_gid, NULL);
                memcpy(header->grh.destination_gid.raw,
                       ah->av->dgid, 16);
        }
index e354b2f04ad9a63d1c70163cf035f31aafbdc3c8..35fe506e2cfa892259a4975919b07355be3df345 100644 (file)
@@ -1476,7 +1476,7 @@ void mthca_free_qp(struct mthca_dev *dev,
 
 /* Create UD header for an MLX send and build a data segment for it */
 static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
-                           int ind, struct ib_send_wr *wr,
+                           int ind, struct ib_ud_wr *wr,
                            struct mthca_mlx_seg *mlx,
                            struct mthca_data_seg *data)
 {
@@ -1485,10 +1485,10 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        u16 pkey;
 
        ib_ud_header_init(256, /* assume a MAD */ 1, 0, 0,
-                         mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0,
+                         mthca_ah_grh_present(to_mah(wr->ah)), 0,
                          &sqp->ud_header);
 
-       err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);
+       err = mthca_read_ah(dev, to_mah(wr->ah), &sqp->ud_header);
        if (err)
                return err;
        mlx->flags &= ~cpu_to_be32(MTHCA_NEXT_SOLICIT | 1);
@@ -1499,7 +1499,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        mlx->rlid = sqp->ud_header.lrh.destination_lid;
        mlx->vcrc = 0;
 
-       switch (wr->opcode) {
+       switch (wr->wr.opcode) {
        case IB_WR_SEND:
                sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY;
                sqp->ud_header.immediate_present = 0;
@@ -1507,7 +1507,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        case IB_WR_SEND_WITH_IMM:
                sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
                sqp->ud_header.immediate_present = 1;
-               sqp->ud_header.immediate_data = wr->ex.imm_data;
+               sqp->ud_header.immediate_data = wr->wr.ex.imm_data;
                break;
        default:
                return -EINVAL;
@@ -1516,18 +1516,18 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
        if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
                sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
-       sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
+       sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
        if (!sqp->qp.ibqp.qp_num)
                ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port,
                                   sqp->pkey_index, &pkey);
        else
                ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port,
-                                  wr->wr.ud.pkey_index, &pkey);
+                                  wr->pkey_index, &pkey);
        sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
-       sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
        sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
-       sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ?
-                                              sqp->qkey : wr->wr.ud.remote_qkey);
+       sqp->ud_header.deth.qkey = cpu_to_be32(wr->remote_qkey & 0x80000000 ?
+                                              sqp->qkey : wr->remote_qkey);
        sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num);
 
        header_size = ib_ud_header_pack(&sqp->ud_header,
@@ -1569,34 +1569,34 @@ static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
 }
 
 static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
-                                          struct ib_send_wr *wr)
+                                          struct ib_atomic_wr *wr)
 {
-       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
-               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       if (wr->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->swap);
+               aseg->compare  = cpu_to_be64(wr->compare_add);
        } else {
-               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->swap_add = cpu_to_be64(wr->compare_add);
                aseg->compare  = 0;
        }
 
 }
 
 static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
-                            struct ib_send_wr *wr)
+                            struct ib_ud_wr *wr)
 {
-       useg->lkey    = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
-       useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
-       useg->dqpn    = cpu_to_be32(wr->wr.ud.remote_qpn);
-       useg->qkey    = cpu_to_be32(wr->wr.ud.remote_qkey);
+       useg->lkey    = cpu_to_be32(to_mah(wr->ah)->key);
+       useg->av_addr = cpu_to_be64(to_mah(wr->ah)->avdma);
+       useg->dqpn    = cpu_to_be32(wr->remote_qpn);
+       useg->qkey    = cpu_to_be32(wr->remote_qkey);
 
 }
 
 static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
-                            struct ib_send_wr *wr)
+                            struct ib_ud_wr *wr)
 {
-       memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
-       useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
-       useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       memcpy(useg->av, to_mah(wr->ah)->av, MTHCA_AV_SIZE);
+       useg->dqpn = cpu_to_be32(wr->remote_qpn);
+       useg->qkey = cpu_to_be32(wr->remote_qkey);
 }
 
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
@@ -1664,11 +1664,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
+                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+                                             atomic_wr(wr)->rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               set_atomic_seg(wqe, wr);
+                               set_atomic_seg(wqe, atomic_wr(wr));
                                wqe += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
@@ -1677,8 +1677,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
                        case IB_WR_RDMA_READ:
-                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
@@ -1694,8 +1694,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
@@ -1708,13 +1708,13 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       set_tavor_ud_seg(wqe, wr);
+                       set_tavor_ud_seg(wqe, ud_wr(wr));
                        wqe  += sizeof (struct mthca_tavor_ud_seg);
                        size += sizeof (struct mthca_tavor_ud_seg) / 16;
                        break;
 
                case MLX:
-                       err = build_mlx_header(dev, to_msqp(qp), ind, wr,
+                       err = build_mlx_header(dev, to_msqp(qp), ind, ud_wr(wr),
                                               wqe - sizeof (struct mthca_next_seg),
                                               wqe);
                        if (err) {
@@ -2005,11 +2005,11 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_ATOMIC_CMP_AND_SWP:
                        case IB_WR_ATOMIC_FETCH_AND_ADD:
-                               set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
-                                             wr->wr.atomic.rkey);
+                               set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
+                                             atomic_wr(wr)->rkey);
                                wqe += sizeof (struct mthca_raddr_seg);
 
-                               set_atomic_seg(wqe, wr);
+                               set_atomic_seg(wqe, atomic_wr(wr));
                                wqe  += sizeof (struct mthca_atomic_seg);
                                size += (sizeof (struct mthca_raddr_seg) +
                                         sizeof (struct mthca_atomic_seg)) / 16;
@@ -2018,8 +2018,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
@@ -2035,8 +2035,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        switch (wr->opcode) {
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_WRITE_WITH_IMM:
-                               set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
-                                             wr->wr.rdma.rkey);
+                               set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
+                                             rdma_wr(wr)->rkey);
                                wqe  += sizeof (struct mthca_raddr_seg);
                                size += sizeof (struct mthca_raddr_seg) / 16;
                                break;
@@ -2049,13 +2049,13 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                        break;
 
                case UD:
-                       set_arbel_ud_seg(wqe, wr);
+                       set_arbel_ud_seg(wqe, ud_wr(wr));
                        wqe  += sizeof (struct mthca_arbel_ud_seg);
                        size += sizeof (struct mthca_arbel_ud_seg) / 16;
                        break;
 
                case MLX:
-                       err = build_mlx_header(dev, to_msqp(qp), ind, wr,
+                       err = build_mlx_header(dev, to_msqp(qp), ind, ud_wr(wr),
                                               wqe - sizeof (struct mthca_next_seg),
                                               wqe);
                        if (err) {
index d748e4b31b8ddf2de875fbd57e7e3277ed0171f8..c9080208aad2ec4b022f915407d61479de40c41f 100644 (file)
@@ -1200,12 +1200,6 @@ struct nes_fast_mr_wqe_pbl {
        dma_addr_t      paddr;
 };
 
-struct nes_ib_fast_reg_page_list {
-       struct ib_fast_reg_page_list    ibfrpl;
-       struct nes_fast_mr_wqe_pbl      nes_wqe_pbl;
-       u64                             pbl;
-};
-
 struct nes_listener {
        struct work_struct      work;
        struct workqueue_struct *wq;
index 44cb513f9a87c0597704422393802cebf70f0f45..137880a19ebe4827bc7f8b419ba6faf9dc50de41 100644 (file)
@@ -51,6 +51,7 @@ atomic_t qps_created;
 atomic_t sw_qps_destroyed;
 
 static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev);
+static int nes_dereg_mr(struct ib_mr *ib_mr);
 
 /**
  * nes_alloc_mw
@@ -443,79 +444,46 @@ static struct ib_mr *nes_alloc_mr(struct ib_pd *ibpd,
        } else {
                kfree(nesmr);
                nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
-               ibmr = ERR_PTR(-ENOMEM);
+               return ERR_PTR(-ENOMEM);
        }
+
+       nesmr->pages = pci_alloc_consistent(nesdev->pcidev,
+                                           max_num_sg * sizeof(u64),
+                                           &nesmr->paddr);
+       if (!nesmr->paddr)
+               goto err;
+
+       nesmr->max_pages = max_num_sg;
+
        return ibmr;
+
+err:
+       nes_dereg_mr(ibmr);
+
+       return ERR_PTR(-ENOMEM);
 }
 
-/*
- * nes_alloc_fast_reg_page_list
- */
-static struct ib_fast_reg_page_list *nes_alloc_fast_reg_page_list(
-                                                       struct ib_device *ibdev,
-                                                       int page_list_len)
+static int nes_set_page(struct ib_mr *ibmr, u64 addr)
 {
-       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
-       struct nes_device *nesdev = nesvnic->nesdev;
-       struct ib_fast_reg_page_list *pifrpl;
-       struct nes_ib_fast_reg_page_list *pnesfrpl;
+       struct nes_mr *nesmr = to_nesmr(ibmr);
 
-       if (page_list_len > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64)))
-               return ERR_PTR(-E2BIG);
-       /*
-        * Allocate the ib_fast_reg_page_list structure, the
-        * nes_fast_bpl structure, and the PLB table.
-        */
-       pnesfrpl = kmalloc(sizeof(struct nes_ib_fast_reg_page_list) +
-                          page_list_len * sizeof(u64), GFP_KERNEL);
-
-       if (!pnesfrpl)
-               return ERR_PTR(-ENOMEM);
+       if (unlikely(nesmr->npages == nesmr->max_pages))
+               return -ENOMEM;
 
-       pifrpl = &pnesfrpl->ibfrpl;
-       pifrpl->page_list = &pnesfrpl->pbl;
-       pifrpl->max_page_list_len = page_list_len;
-       /*
-        * Allocate the WQE PBL
-        */
-       pnesfrpl->nes_wqe_pbl.kva = pci_alloc_consistent(nesdev->pcidev,
-                                                        page_list_len * sizeof(u64),
-                                                        &pnesfrpl->nes_wqe_pbl.paddr);
+       nesmr->pages[nesmr->npages++] = cpu_to_le64(addr);
 
-       if (!pnesfrpl->nes_wqe_pbl.kva) {
-               kfree(pnesfrpl);
-               return ERR_PTR(-ENOMEM);
-       }
-       nes_debug(NES_DBG_MR, "nes_alloc_fast_reg_pbl: nes_frpl = %p, "
-                 "ibfrpl = %p, ibfrpl.page_list = %p, pbl.kva = %p, "
-                 "pbl.paddr = %llx\n", pnesfrpl, &pnesfrpl->ibfrpl,
-                 pnesfrpl->ibfrpl.page_list, pnesfrpl->nes_wqe_pbl.kva,
-                 (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr);
-
-       return pifrpl;
+       return 0;
 }
 
-/*
- * nes_free_fast_reg_page_list
- */
-static void nes_free_fast_reg_page_list(struct ib_fast_reg_page_list *pifrpl)
+static int nes_map_mr_sg(struct ib_mr *ibmr,
+                        struct scatterlist *sg,
+                        int sg_nents)
 {
-       struct nes_vnic *nesvnic = to_nesvnic(pifrpl->device);
-       struct nes_device *nesdev = nesvnic->nesdev;
-       struct nes_ib_fast_reg_page_list *pnesfrpl;
+       struct nes_mr *nesmr = to_nesmr(ibmr);
 
-       pnesfrpl = container_of(pifrpl, struct nes_ib_fast_reg_page_list, ibfrpl);
-       /*
-        * Free the WQE PBL.
-        */
-       pci_free_consistent(nesdev->pcidev,
-                           pifrpl->max_page_list_len * sizeof(u64),
-                           pnesfrpl->nes_wqe_pbl.kva,
-                           pnesfrpl->nes_wqe_pbl.paddr);
-       /*
-        * Free the PBL structure
-        */
-       kfree(pnesfrpl);
+       nesmr->npages = 0;
+
+       return ib_sg_to_pages(ibmr, sg, sg_nents, nes_set_page);
 }
 
 /**
@@ -2683,6 +2651,13 @@ static int nes_dereg_mr(struct ib_mr *ib_mr)
        u16 major_code;
        u16 minor_code;
 
+
+       if (nesmr->pages)
+               pci_free_consistent(nesdev->pcidev,
+                                   nesmr->max_pages * sizeof(u64),
+                                   nesmr->pages,
+                                   nesmr->paddr);
+
        if (nesmr->region) {
                ib_umem_release(nesmr->region);
        }
@@ -3372,9 +3347,9 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                                wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
 
                        set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
-                                           ib_wr->wr.rdma.rkey);
+                                           rdma_wr(ib_wr)->rkey);
                        set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
-                                           ib_wr->wr.rdma.remote_addr);
+                                           rdma_wr(ib_wr)->remote_addr);
 
                        if ((ib_wr->send_flags & IB_SEND_INLINE) &&
                            ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
@@ -3409,9 +3384,9 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                        }
 
                        set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
-                                           ib_wr->wr.rdma.remote_addr);
+                                           rdma_wr(ib_wr)->remote_addr);
                        set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
-                                           ib_wr->wr.rdma.rkey);
+                                           rdma_wr(ib_wr)->rkey);
                        set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX,
                                            ib_wr->sg_list->length);
                        set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
@@ -3425,19 +3400,13 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                                            NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX,
                                            ib_wr->ex.invalidate_rkey);
                        break;
-               case IB_WR_FAST_REG_MR:
+               case IB_WR_REG_MR:
                {
-                       int i;
-                       int flags = ib_wr->wr.fast_reg.access_flags;
-                       struct nes_ib_fast_reg_page_list *pnesfrpl =
-                               container_of(ib_wr->wr.fast_reg.page_list,
-                                            struct nes_ib_fast_reg_page_list,
-                                            ibfrpl);
-                       u64 *src_page_list = pnesfrpl->ibfrpl.page_list;
-                       u64 *dst_page_list = pnesfrpl->nes_wqe_pbl.kva;
-
-                       if (ib_wr->wr.fast_reg.page_list_len >
-                           (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) {
+                       struct nes_mr *mr = to_nesmr(reg_wr(ib_wr)->mr);
+                       int page_shift = ilog2(reg_wr(ib_wr)->mr->page_size);
+                       int flags = reg_wr(ib_wr)->access;
+
+                       if (mr->npages > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) {
                                nes_debug(NES_DBG_IW_TX, "SQ_FMR: bad page_list_len\n");
                                err = -EINVAL;
                                break;
@@ -3445,19 +3414,19 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                        wqe_misc = NES_IWARP_SQ_OP_FAST_REG;
                        set_wqe_64bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX,
-                                           ib_wr->wr.fast_reg.iova_start);
+                                           mr->ibmr.iova);
                        set_wqe_32bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX,
-                                           ib_wr->wr.fast_reg.length);
+                                           mr->ibmr.length);
                        set_wqe_32bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0);
                        set_wqe_32bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX,
-                                           ib_wr->wr.fast_reg.rkey);
-                       /* Set page size: */
-                       if (ib_wr->wr.fast_reg.page_shift == 12) {
+                                           reg_wr(ib_wr)->key);
+
+                       if (page_shift == 12) {
                                wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_4K;
-                       } else if (ib_wr->wr.fast_reg.page_shift == 21) {
+                       } else if (page_shift == 21) {
                                wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_2M;
                        } else {
                                nes_debug(NES_DBG_IW_TX, "Invalid page shift,"
@@ -3465,6 +3434,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                                err = -EINVAL;
                                break;
                        }
+
                        /* Set access_flags */
                        wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_READ;
                        if (flags & IB_ACCESS_LOCAL_WRITE)
@@ -3480,35 +3450,22 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                                wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_WINDOW_BIND;
 
                        /* Fill in PBL info: */
-                       if (ib_wr->wr.fast_reg.page_list_len >
-                           pnesfrpl->ibfrpl.max_page_list_len) {
-                               nes_debug(NES_DBG_IW_TX, "Invalid page list length,"
-                                         " ib_wr=%p, value=%u, max=%u\n",
-                                         ib_wr, ib_wr->wr.fast_reg.page_list_len,
-                                         pnesfrpl->ibfrpl.max_page_list_len);
-                               err = -EINVAL;
-                               break;
-                       }
-
                        set_wqe_64bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX,
-                                           pnesfrpl->nes_wqe_pbl.paddr);
+                                           mr->paddr);
 
                        set_wqe_32bit_value(wqe->wqe_words,
                                            NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX,
-                                           ib_wr->wr.fast_reg.page_list_len * 8);
-
-                       for (i = 0; i < ib_wr->wr.fast_reg.page_list_len; i++)
-                               dst_page_list[i] = cpu_to_le64(src_page_list[i]);
+                                           mr->npages * 8);
 
-                       nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %llx, "
+                       nes_debug(NES_DBG_IW_TX, "SQ_REG_MR: iova_start: %llx, "
                                  "length: %d, rkey: %0x, pgl_paddr: %llx, "
                                  "page_list_len: %u, wqe_misc: %x\n",
-                                 (unsigned long long) ib_wr->wr.fast_reg.iova_start,
-                                 ib_wr->wr.fast_reg.length,
-                                 ib_wr->wr.fast_reg.rkey,
-                                 (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr,
-                                 ib_wr->wr.fast_reg.page_list_len,
+                                 (unsigned long long) mr->ibmr.iova,
+                                 mr->ibmr.length,
+                                 reg_wr(ib_wr)->key,
+                                 (unsigned long long) mr->paddr,
+                                 mr->npages,
                                  wqe_misc);
                        break;
                }
@@ -3751,7 +3708,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
                                                entry->opcode = IB_WC_LOCAL_INV;
                                                break;
                                        case NES_IWARP_SQ_OP_FAST_REG:
-                                               entry->opcode = IB_WC_FAST_REG_MR;
+                                               entry->opcode = IB_WC_REG_MR;
                                                break;
                                }
 
@@ -3939,8 +3896,7 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
        nesibdev->ibdev.bind_mw = nes_bind_mw;
 
        nesibdev->ibdev.alloc_mr = nes_alloc_mr;
-       nesibdev->ibdev.alloc_fast_reg_page_list = nes_alloc_fast_reg_page_list;
-       nesibdev->ibdev.free_fast_reg_page_list = nes_free_fast_reg_page_list;
+       nesibdev->ibdev.map_mr_sg = nes_map_mr_sg;
 
        nesibdev->ibdev.attach_mcast = nes_multicast_attach;
        nesibdev->ibdev.detach_mcast = nes_multicast_detach;
index 309b31c31ae1ac5e9b7bcd44701f22d65e0a1630..a204b677af22a8d00fba4b5b65bc0620d4cb7a1c 100644 (file)
@@ -79,6 +79,10 @@ struct nes_mr {
        u16               pbls_used;
        u8                mode;
        u8                pbl_4k;
+       __le64            *pages;
+       dma_addr_t        paddr;
+       u32               max_pages;
+       u32               npages;
 };
 
 struct nes_hw_pb {
index b4091ab48db0bc86d8edf42cb76661c5d6b44b52..ae80590aabdf7db6df756c0ee07afa4721f6c37c 100644 (file)
@@ -55,7 +55,7 @@
 #include <be_roce.h>
 #include "ocrdma_sli.h"
 
-#define OCRDMA_ROCE_DRV_VERSION "10.6.0.0"
+#define OCRDMA_ROCE_DRV_VERSION "11.0.0.0"
 
 #define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
 #define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
@@ -193,6 +193,8 @@ struct ocrdma_mr {
        struct ib_mr ibmr;
        struct ib_umem *umem;
        struct ocrdma_hw_mr hwmr;
+       u64 *pages;
+       u32 npages;
 };
 
 struct ocrdma_stats {
@@ -278,7 +280,6 @@ struct ocrdma_dev {
        u32 hba_port_num;
 
        struct list_head entry;
-       struct rcu_head rcu;
        int id;
        u64 *stag_arr;
        u8 sl; /* service level */
index 44766fee1f4e2cacb2d971f7858ad6e3eb4c4875..9820074be59d73bd1aac4b56d4a38254d2f9b7bb 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <rdma/ib_addr.h>
 #include <rdma/ib_mad.h>
+#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_verbs.h"
 
 static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
                        struct ib_ah_attr *attr, union ib_gid *sgid,
-                       int pdid, bool *isvlan)
+                       int pdid, bool *isvlan, u16 vlan_tag)
 {
        int status = 0;
-       u16 vlan_tag;
        struct ocrdma_eth_vlan eth;
        struct ocrdma_grh grh;
        int eth_sz;
@@ -68,7 +68,6 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
        memset(&grh, 0, sizeof(grh));
 
        /* VLAN */
-       vlan_tag = attr->vlan_id;
        if (!vlan_tag || (vlan_tag > 0xFFF))
                vlan_tag = dev->pvid;
        if (vlan_tag || dev->pfc_state) {
@@ -115,9 +114,11 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
 struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
 {
        u32 *ahid_addr;
-       bool isvlan = false;
        int status;
        struct ocrdma_ah *ah;
+       bool isvlan = false;
+       u16 vlan_tag = 0xffff;
+       struct ib_gid_attr sgid_attr;
        struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
        struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device);
        union ib_gid sgid;
@@ -135,18 +136,25 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
        if (status)
                goto av_err;
 
-       status = ocrdma_query_gid(&dev->ibdev, 1, attr->grh.sgid_index, &sgid);
+       status = ib_get_cached_gid(&dev->ibdev, 1, attr->grh.sgid_index, &sgid,
+                                  &sgid_attr);
        if (status) {
                pr_err("%s(): Failed to query sgid, status = %d\n",
                      __func__, status);
                goto av_conf_err;
        }
+       if (sgid_attr.ndev) {
+               if (is_vlan_dev(sgid_attr.ndev))
+                       vlan_tag = vlan_dev_vlan_id(sgid_attr.ndev);
+               dev_put(sgid_attr.ndev);
+       }
 
        if ((pd->uctx) &&
            (!rdma_is_multicast_addr((struct in6_addr *)attr->grh.dgid.raw)) &&
            (!rdma_link_local_addr((struct in6_addr *)attr->grh.dgid.raw))) {
                status = rdma_addr_find_dmac_by_grh(&sgid, &attr->grh.dgid,
-                                        attr->dmac, &attr->vlan_id);
+                                                   attr->dmac, &vlan_tag,
+                                                   sgid_attr.ndev->ifindex);
                if (status) {
                        pr_err("%s(): Failed to resolve dmac from gid." 
                                "status = %d\n", __func__, status);
@@ -154,7 +162,7 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
                }
        }
 
-       status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan);
+       status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan, vlan_tag);
        if (status)
                goto av_conf_err;
 
index aab391a15db429104f52765346455ba07efa424b..30f67bebffa35742189c4fc08b91654f75bfdcfa 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_hw.h"
@@ -678,11 +679,33 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
        int dev_event = 0;
        int type = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_TYPE_MASK) >>
            OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT;
+       u16 qpid = cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK;
+       u16 cqid = cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK;
 
-       if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID)
-               qp = dev->qp_tbl[cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK];
-       if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID)
-               cq = dev->cq_tbl[cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK];
+       /*
+        * Some FW version returns wrong qp or cq ids in CQEs.
+        * Checking whether the IDs are valid
+        */
+
+       if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID) {
+               if (qpid < dev->attr.max_qp)
+                       qp = dev->qp_tbl[qpid];
+               if (qp == NULL) {
+                       pr_err("ocrdma%d:Async event - qpid %u is not valid\n",
+                              dev->id, qpid);
+                       return;
+               }
+       }
+
+       if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID) {
+               if (cqid < dev->attr.max_cq)
+                       cq = dev->cq_tbl[cqid];
+               if (cq == NULL) {
+                       pr_err("ocrdma%d:Async event - cqid %u is not valid\n",
+                              dev->id, cqid);
+                       return;
+               }
+       }
 
        memset(&ib_evt, 0, sizeof(ib_evt));
 
@@ -2448,6 +2471,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        int status;
        struct ib_ah_attr *ah_attr = &attrs->ah_attr;
        union ib_gid sgid, zgid;
+       struct ib_gid_attr sgid_attr;
        u32 vlan_id = 0xFFFF;
        u8 mac_addr[6];
        struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
@@ -2466,10 +2490,14 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
        memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
               sizeof(cmd->params.dgid));
-       status = ocrdma_query_gid(&dev->ibdev, 1,
-                       ah_attr->grh.sgid_index, &sgid);
-       if (status)
-               return status;
+
+       status = ib_get_cached_gid(&dev->ibdev, 1, ah_attr->grh.sgid_index,
+                                  &sgid, &sgid_attr);
+       if (!status && sgid_attr.ndev) {
+               vlan_id = rdma_vlan_dev_vlan_id(sgid_attr.ndev);
+               memcpy(mac_addr, sgid_attr.ndev->dev_addr, ETH_ALEN);
+               dev_put(sgid_attr.ndev);
+       }
 
        memset(&zgid, 0, sizeof(zgid));
        if (!memcmp(&sgid, &zgid, sizeof(zgid)))
@@ -2486,17 +2514,15 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        ocrdma_cpu_to_le32(&cmd->params.dgid[0], sizeof(cmd->params.dgid));
        ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
        cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
-       if (attr_mask & IB_QP_VID) {
-               vlan_id = attrs->vlan_id;
-       } else if (dev->pfc_state) {
-               vlan_id = 0;
-               pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
-                       dev->id);
-               pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
-                       dev->id);
-       }
 
        if (vlan_id < 0x1000) {
+               if (dev->pfc_state) {
+                       vlan_id = 0;
+                       pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
+                              dev->id);
+                       pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
+                              dev->id);
+               }
                cmd->params.vlan_dmac_b4_to_b5 |=
                    vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
                cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
index 87aa55df7c8211f6f8fbc441d0133b86878387ec..62b7009daa6c18a4d21002636637b5a2d258b231 100644 (file)
@@ -63,8 +63,6 @@ MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION);
 MODULE_AUTHOR("Emulex Corporation");
 MODULE_LICENSE("Dual BSD/GPL");
 
-static LIST_HEAD(ocrdma_dev_list);
-static DEFINE_SPINLOCK(ocrdma_devlist_lock);
 static DEFINE_IDR(ocrdma_dev_id);
 
 void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid)
@@ -182,8 +180,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
        dev->ibdev.reg_user_mr = ocrdma_reg_user_mr;
 
        dev->ibdev.alloc_mr = ocrdma_alloc_mr;
-       dev->ibdev.alloc_fast_reg_page_list = ocrdma_alloc_frmr_page_list;
-       dev->ibdev.free_fast_reg_page_list = ocrdma_free_frmr_page_list;
+       dev->ibdev.map_mr_sg = ocrdma_map_mr_sg;
 
        /* mandatory to support user space verbs consumer. */
        dev->ibdev.alloc_ucontext = ocrdma_alloc_ucontext;
@@ -325,9 +322,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
        for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
                if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
                        goto sysfs_err;
-       spin_lock(&ocrdma_devlist_lock);
-       list_add_tail_rcu(&dev->entry, &ocrdma_dev_list);
-       spin_unlock(&ocrdma_devlist_lock);
        /* Init stats */
        ocrdma_add_port_stats(dev);
        /* Interrupt Moderation */
@@ -356,9 +350,8 @@ idr_err:
        return NULL;
 }
 
-static void ocrdma_remove_free(struct rcu_head *rcu)
+static void ocrdma_remove_free(struct ocrdma_dev *dev)
 {
-       struct ocrdma_dev *dev = container_of(rcu, struct ocrdma_dev, rcu);
 
        idr_remove(&ocrdma_dev_id, dev->id);
        kfree(dev->mbx_cmd);
@@ -375,15 +368,9 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
        ib_unregister_device(&dev->ibdev);
 
        ocrdma_rem_port_stats(dev);
-
-       spin_lock(&ocrdma_devlist_lock);
-       list_del_rcu(&dev->entry);
-       spin_unlock(&ocrdma_devlist_lock);
-
        ocrdma_free_resources(dev);
        ocrdma_cleanup_hw(dev);
-
-       call_rcu(&dev->rcu, ocrdma_remove_free);
+       ocrdma_remove_free(dev);
 }
 
 static int ocrdma_open(struct ocrdma_dev *dev)
index 69334e214571b94ae0305bc8c9821aa0e261b7fe..86c303a620c1660625ebb94f1b54e578856b26ff 100644 (file)
@@ -855,9 +855,9 @@ void ocrdma_rem_port_stats(struct ocrdma_dev *dev)
 {
        if (!dev->dir)
                return;
+       debugfs_remove(dev->dir);
        mutex_destroy(&dev->stats_lock);
        ocrdma_release_stats_mem(dev);
-       debugfs_remove(dev->dir);
 }
 
 void ocrdma_init_debugfs(void)
index 1f3affb6a477156dec43694d80b70b3b8339c27d..583001bcfb8fc8c10a1e088b451d7de12adc2aa8 100644 (file)
@@ -73,7 +73,7 @@ int ocrdma_query_gid(struct ib_device *ibdev, u8 port,
        if (index >= OCRDMA_MAX_SGID)
                return -EINVAL;
 
-       ret = ib_get_cached_gid(ibdev, port, index, sgid);
+       ret = ib_get_cached_gid(ibdev, port, index, sgid, NULL);
        if (ret == -EAGAIN) {
                memcpy(sgid, &zgid, sizeof(*sgid));
                return 0;
@@ -1013,6 +1013,7 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
 
        (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
 
+       kfree(mr->pages);
        ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
 
        /* it could be user registered memory. */
@@ -1997,13 +1998,13 @@ static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,
 {
        struct ocrdma_ewqe_ud_hdr *ud_hdr =
                (struct ocrdma_ewqe_ud_hdr *)(hdr + 1);
-       struct ocrdma_ah *ah = get_ocrdma_ah(wr->wr.ud.ah);
+       struct ocrdma_ah *ah = get_ocrdma_ah(ud_wr(wr)->ah);
 
-       ud_hdr->rsvd_dest_qpn = wr->wr.ud.remote_qpn;
+       ud_hdr->rsvd_dest_qpn = ud_wr(wr)->remote_qpn;
        if (qp->qp_type == IB_QPT_GSI)
                ud_hdr->qkey = qp->qkey;
        else
-               ud_hdr->qkey = wr->wr.ud.remote_qkey;
+               ud_hdr->qkey = ud_wr(wr)->remote_qkey;
        ud_hdr->rsvd_ahid = ah->id;
        if (ah->av->valid & OCRDMA_AV_VLAN_VALID)
                hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT);
@@ -2106,9 +2107,9 @@ static int ocrdma_build_write(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
        status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size);
        if (status)
                return status;
-       ext_rw->addr_lo = wr->wr.rdma.remote_addr;
-       ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);
-       ext_rw->lrkey = wr->wr.rdma.rkey;
+       ext_rw->addr_lo = rdma_wr(wr)->remote_addr;
+       ext_rw->addr_hi = upper_32_bits(rdma_wr(wr)->remote_addr);
+       ext_rw->lrkey = rdma_wr(wr)->rkey;
        ext_rw->len = hdr->total_len;
        return 0;
 }
@@ -2126,46 +2127,12 @@ static void ocrdma_build_read(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
        hdr->cw |= (OCRDMA_READ << OCRDMA_WQE_OPCODE_SHIFT);
        hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);
 
-       ext_rw->addr_lo = wr->wr.rdma.remote_addr;
-       ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);
-       ext_rw->lrkey = wr->wr.rdma.rkey;
+       ext_rw->addr_lo = rdma_wr(wr)->remote_addr;
+       ext_rw->addr_hi = upper_32_bits(rdma_wr(wr)->remote_addr);
+       ext_rw->lrkey = rdma_wr(wr)->rkey;
        ext_rw->len = hdr->total_len;
 }
 
-static void build_frmr_pbes(struct ib_send_wr *wr, struct ocrdma_pbl *pbl_tbl,
-                           struct ocrdma_hw_mr *hwmr)
-{
-       int i;
-       u64 buf_addr = 0;
-       int num_pbes;
-       struct ocrdma_pbe *pbe;
-
-       pbe = (struct ocrdma_pbe *)pbl_tbl->va;
-       num_pbes = 0;
-
-       /* go through the OS phy regions & fill hw pbe entries into pbls. */
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-               /* number of pbes can be more for one OS buf, when
-                * buffers are of different sizes.
-                * split the ib_buf to one or more pbes.
-                */
-               buf_addr = wr->wr.fast_reg.page_list->page_list[i];
-               pbe->pa_lo = cpu_to_le32((u32) (buf_addr & PAGE_MASK));
-               pbe->pa_hi = cpu_to_le32((u32) upper_32_bits(buf_addr));
-               num_pbes += 1;
-               pbe++;
-
-               /* if the pbl is full storing the pbes,
-                * move to next pbl.
-               */
-               if (num_pbes == (hwmr->pbl_size/sizeof(u64))) {
-                       pbl_tbl++;
-                       pbe = (struct ocrdma_pbe *)pbl_tbl->va;
-               }
-       }
-       return;
-}
-
 static int get_encoded_page_size(int pg_sz)
 {
        /* Max size is 256M 4096 << 16 */
@@ -2176,48 +2143,59 @@ static int get_encoded_page_size(int pg_sz)
        return i;
 }
 
-
-static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
-                          struct ib_send_wr *wr)
+static int ocrdma_build_reg(struct ocrdma_qp *qp,
+                           struct ocrdma_hdr_wqe *hdr,
+                           struct ib_reg_wr *wr)
 {
        u64 fbo;
        struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1);
-       struct ocrdma_mr *mr;
-       struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       struct ocrdma_mr *mr = get_ocrdma_mr(wr->mr);
+       struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table;
+       struct ocrdma_pbe *pbe;
        u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr);
+       int num_pbes = 0, i;
 
        wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES);
 
-       if (wr->wr.fast_reg.page_list_len > dev->attr.max_pages_per_frmr)
-               return -EINVAL;
-
        hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT);
        hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT);
 
-       if (wr->wr.fast_reg.page_list_len == 0)
-               BUG();
-       if (wr->wr.fast_reg.access_flags & IB_ACCESS_LOCAL_WRITE)
+       if (wr->access & IB_ACCESS_LOCAL_WRITE)
                hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_LOCAL_WR;
-       if (wr->wr.fast_reg.access_flags & IB_ACCESS_REMOTE_WRITE)
+       if (wr->access & IB_ACCESS_REMOTE_WRITE)
                hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_REMOTE_WR;
-       if (wr->wr.fast_reg.access_flags & IB_ACCESS_REMOTE_READ)
+       if (wr->access & IB_ACCESS_REMOTE_READ)
                hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_REMOTE_RD;
-       hdr->lkey = wr->wr.fast_reg.rkey;
-       hdr->total_len = wr->wr.fast_reg.length;
+       hdr->lkey = wr->key;
+       hdr->total_len = mr->ibmr.length;
 
-       fbo = wr->wr.fast_reg.iova_start -
-           (wr->wr.fast_reg.page_list->page_list[0] & PAGE_MASK);
+       fbo = mr->ibmr.iova - mr->pages[0];
 
-       fast_reg->va_hi = upper_32_bits(wr->wr.fast_reg.iova_start);
-       fast_reg->va_lo = (u32) (wr->wr.fast_reg.iova_start & 0xffffffff);
+       fast_reg->va_hi = upper_32_bits(mr->ibmr.iova);
+       fast_reg->va_lo = (u32) (mr->ibmr.iova & 0xffffffff);
        fast_reg->fbo_hi = upper_32_bits(fbo);
        fast_reg->fbo_lo = (u32) fbo & 0xffffffff;
-       fast_reg->num_sges = wr->wr.fast_reg.page_list_len;
-       fast_reg->size_sge =
-               get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
-       mr = (struct ocrdma_mr *) (unsigned long)
-               dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
-       build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
+       fast_reg->num_sges = mr->npages;
+       fast_reg->size_sge = get_encoded_page_size(mr->ibmr.page_size);
+
+       pbe = pbl_tbl->va;
+       for (i = 0; i < mr->npages; i++) {
+               u64 buf_addr = mr->pages[i];
+
+               pbe->pa_lo = cpu_to_le32((u32) (buf_addr & PAGE_MASK));
+               pbe->pa_hi = cpu_to_le32((u32) upper_32_bits(buf_addr));
+               num_pbes += 1;
+               pbe++;
+
+               /* if the pbl is full storing the pbes,
+                * move to next pbl.
+               */
+               if (num_pbes == (mr->hwmr.pbl_size/sizeof(u64))) {
+                       pbl_tbl++;
+                       pbe = (struct ocrdma_pbe *)pbl_tbl->va;
+               }
+       }
+
        return 0;
 }
 
@@ -2300,8 +2278,8 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT;
                        hdr->lkey = wr->ex.invalidate_rkey;
                        break;
-               case IB_WR_FAST_REG_MR:
-                       status = ocrdma_build_fr(qp, hdr, wr);
+               case IB_WR_REG_MR:
+                       status = ocrdma_build_reg(qp, hdr, reg_wr(wr));
                        break;
                default:
                        status = -EINVAL;
@@ -2567,7 +2545,7 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
                ibwc->opcode = IB_WC_SEND;
                break;
        case OCRDMA_FR_MR:
-               ibwc->opcode = IB_WC_FAST_REG_MR;
+               ibwc->opcode = IB_WC_REG_MR;
                break;
        case OCRDMA_LKEY_INV:
                ibwc->opcode = IB_WC_LOCAL_INV;
@@ -2933,16 +2911,11 @@ expand_cqe:
        }
 stop_cqe:
        cq->getp = cur_getp;
-       if (cq->deferred_arm) {
-               ocrdma_ring_cq_db(dev, cq->id, true, cq->deferred_sol,
-                                 polled_hw_cqes);
+       if (cq->deferred_arm || polled_hw_cqes) {
+               ocrdma_ring_cq_db(dev, cq->id, cq->deferred_arm,
+                                 cq->deferred_sol, polled_hw_cqes);
                cq->deferred_arm = false;
                cq->deferred_sol = false;
-       } else {
-               /* We need to pop the CQE. No need to arm */
-               ocrdma_ring_cq_db(dev, cq->id, false, cq->deferred_sol,
-                                 polled_hw_cqes);
-               cq->deferred_sol = false;
        }
 
        return i;
@@ -3058,6 +3031,12 @@ struct ib_mr *ocrdma_alloc_mr(struct ib_pd *ibpd,
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
+       mr->pages = kcalloc(max_num_sg, sizeof(u64), GFP_KERNEL);
+       if (!mr->pages) {
+               status = -ENOMEM;
+               goto pl_err;
+       }
+
        status = ocrdma_get_pbl_info(dev, mr, max_num_sg);
        if (status)
                goto pbl_err;
@@ -3081,30 +3060,12 @@ struct ib_mr *ocrdma_alloc_mr(struct ib_pd *ibpd,
 mbx_err:
        ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
 pbl_err:
+       kfree(mr->pages);
+pl_err:
        kfree(mr);
        return ERR_PTR(-ENOMEM);
 }
 
-struct ib_fast_reg_page_list *ocrdma_alloc_frmr_page_list(struct ib_device
-                                                         *ibdev,
-                                                         int page_list_len)
-{
-       struct ib_fast_reg_page_list *frmr_list;
-       int size;
-
-       size = sizeof(*frmr_list) + (page_list_len * sizeof(u64));
-       frmr_list = kzalloc(size, GFP_KERNEL);
-       if (!frmr_list)
-               return ERR_PTR(-ENOMEM);
-       frmr_list->page_list = (u64 *)(frmr_list + 1);
-       return frmr_list;
-}
-
-void ocrdma_free_frmr_page_list(struct ib_fast_reg_page_list *page_list)
-{
-       kfree(page_list);
-}
-
 #define MAX_KERNEL_PBE_SIZE 65536
 static inline int count_kernel_pbes(struct ib_phys_buf *buf_list,
                                    int buf_cnt, u32 *pbe_size)
@@ -3267,3 +3228,26 @@ pbl_err:
        kfree(mr);
        return ERR_PTR(status);
 }
+
+static int ocrdma_set_page(struct ib_mr *ibmr, u64 addr)
+{
+       struct ocrdma_mr *mr = get_ocrdma_mr(ibmr);
+
+       if (unlikely(mr->npages == mr->hwmr.num_pbes))
+               return -ENOMEM;
+
+       mr->pages[mr->npages++] = addr;
+
+       return 0;
+}
+
+int ocrdma_map_mr_sg(struct ib_mr *ibmr,
+                    struct scatterlist *sg,
+                    int sg_nents)
+{
+       struct ocrdma_mr *mr = get_ocrdma_mr(ibmr);
+
+       mr->npages = 0;
+
+       return ib_sg_to_pages(ibmr, sg, sg_nents, ocrdma_set_page);
+}
index 308c16857a5d03e2d3605136abdf8d3b11ad5361..a2f3b4dc20b0363d0a09769aaee2d69dd957ae33 100644 (file)
@@ -125,9 +125,8 @@ struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *, u64 start, u64 length,
 struct ib_mr *ocrdma_alloc_mr(struct ib_pd *pd,
                              enum ib_mr_type mr_type,
                              u32 max_num_sg);
-struct ib_fast_reg_page_list *ocrdma_alloc_frmr_page_list(struct ib_device
-                                                       *ibdev,
-                                                       int page_list_len);
-void ocrdma_free_frmr_page_list(struct ib_fast_reg_page_list *page_list);
+int ocrdma_map_mr_sg(struct ib_mr *ibmr,
+                    struct scatterlist *sg,
+                    int sg_nents);
 
 #endif                         /* __OCRDMA_VERBS_H__ */
index 5afaa218508d222f901252194c5872a18a79be90..d725c565518dc86aee6354390c06e5224c6596d8 100644 (file)
@@ -336,14 +336,15 @@ bail:
 }
 
 /*
- * Initialize the memory region specified by the work reqeust.
+ * Initialize the memory region specified by the work request.
  */
-int qib_fast_reg_mr(struct qib_qp *qp, struct ib_send_wr *wr)
+int qib_reg_mr(struct qib_qp *qp, struct ib_reg_wr *wr)
 {
        struct qib_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
        struct qib_pd *pd = to_ipd(qp->ibqp.pd);
-       struct qib_mregion *mr;
-       u32 rkey = wr->wr.fast_reg.rkey;
+       struct qib_mr *mr = to_imr(wr->mr);
+       struct qib_mregion *mrg;
+       u32 key = wr->key;
        unsigned i, n, m;
        int ret = -EINVAL;
        unsigned long flags;
@@ -351,33 +352,33 @@ int qib_fast_reg_mr(struct qib_qp *qp, struct ib_send_wr *wr)
        size_t ps;
 
        spin_lock_irqsave(&rkt->lock, flags);
-       if (pd->user || rkey == 0)
+       if (pd->user || key == 0)
                goto bail;
 
-       mr = rcu_dereference_protected(
-               rkt->table[(rkey >> (32 - ib_qib_lkey_table_size))],
+       mrg = rcu_dereference_protected(
+               rkt->table[(key >> (32 - ib_qib_lkey_table_size))],
                lockdep_is_held(&rkt->lock));
-       if (unlikely(mr == NULL || qp->ibqp.pd != mr->pd))
+       if (unlikely(mrg == NULL || qp->ibqp.pd != mrg->pd))
                goto bail;
 
-       if (wr->wr.fast_reg.page_list_len > mr->max_segs)
+       if (mr->npages > mrg->max_segs)
                goto bail;
 
-       ps = 1UL << wr->wr.fast_reg.page_shift;
-       if (wr->wr.fast_reg.length > ps * wr->wr.fast_reg.page_list_len)
+       ps = mr->ibmr.page_size;
+       if (mr->ibmr.length > ps * mr->npages)
                goto bail;
 
-       mr->user_base = wr->wr.fast_reg.iova_start;
-       mr->iova = wr->wr.fast_reg.iova_start;
-       mr->lkey = rkey;
-       mr->length = wr->wr.fast_reg.length;
-       mr->access_flags = wr->wr.fast_reg.access_flags;
-       page_list = wr->wr.fast_reg.page_list->page_list;
+       mrg->user_base = mr->ibmr.iova;
+       mrg->iova = mr->ibmr.iova;
+       mrg->lkey = key;
+       mrg->length = mr->ibmr.length;
+       mrg->access_flags = wr->access;
+       page_list = mr->pages;
        m = 0;
        n = 0;
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-               mr->map[m]->segs[n].vaddr = (void *) page_list[i];
-               mr->map[m]->segs[n].length = ps;
+       for (i = 0; i < mr->npages; i++) {
+               mrg->map[m]->segs[n].vaddr = (void *) page_list[i];
+               mrg->map[m]->segs[n].length = ps;
                if (++n == QIB_SEGSZ) {
                        m++;
                        n = 0;
index 19220dcb9a3b2a1ea00e4aed2d87eef09269a92d..294f5c706be972b4b6563e37a32064fade665be2 100644 (file)
@@ -303,6 +303,7 @@ int qib_dereg_mr(struct ib_mr *ibmr)
        int ret = 0;
        unsigned long timeout;
 
+       kfree(mr->pages);
        qib_free_lkey(&mr->mr);
 
        qib_put_mr(&mr->mr); /* will set completion if last */
@@ -323,7 +324,7 @@ out:
 
 /*
  * Allocate a memory region usable with the
- * IB_WR_FAST_REG_MR send work request.
+ * IB_WR_REG_MR send work request.
  *
  * Return the memory region on success, otherwise return an errno.
  */
@@ -340,37 +341,38 @@ struct ib_mr *qib_alloc_mr(struct ib_pd *pd,
        if (IS_ERR(mr))
                return (struct ib_mr *)mr;
 
+       mr->pages = kcalloc(max_num_sg, sizeof(u64), GFP_KERNEL);
+       if (!mr->pages)
+               goto err;
+
        return &mr->ibmr;
+
+err:
+       qib_dereg_mr(&mr->ibmr);
+       return ERR_PTR(-ENOMEM);
 }
 
-struct ib_fast_reg_page_list *
-qib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len)
+static int qib_set_page(struct ib_mr *ibmr, u64 addr)
 {
-       unsigned size = page_list_len * sizeof(u64);
-       struct ib_fast_reg_page_list *pl;
-
-       if (size > PAGE_SIZE)
-               return ERR_PTR(-EINVAL);
-
-       pl = kzalloc(sizeof(*pl), GFP_KERNEL);
-       if (!pl)
-               return ERR_PTR(-ENOMEM);
+       struct qib_mr *mr = to_imr(ibmr);
 
-       pl->page_list = kzalloc(size, GFP_KERNEL);
-       if (!pl->page_list)
-               goto err_free;
+       if (unlikely(mr->npages == mr->mr.max_segs))
+               return -ENOMEM;
 
-       return pl;
+       mr->pages[mr->npages++] = addr;
 
-err_free:
-       kfree(pl);
-       return ERR_PTR(-ENOMEM);
+       return 0;
 }
 
-void qib_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl)
+int qib_map_mr_sg(struct ib_mr *ibmr,
+                 struct scatterlist *sg,
+                 int sg_nents)
 {
-       kfree(pl->page_list);
-       kfree(pl);
+       struct qib_mr *mr = to_imr(ibmr);
+
+       mr->npages = 0;
+
+       return ib_sg_to_pages(ibmr, sg, sg_nents, qib_set_page);
 }
 
 /**
index 4fa88ba2963e6ba21186ae5eb095ea531b741e97..40f85bb3e0d3bdce5289a5c8c9c2418df33e4ca4 100644 (file)
@@ -436,7 +436,7 @@ static void clear_mr_refs(struct qib_qp *qp, int clr_sends)
                        if (qp->ibqp.qp_type == IB_QPT_UD ||
                            qp->ibqp.qp_type == IB_QPT_SMI ||
                            qp->ibqp.qp_type == IB_QPT_GSI)
-                               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+                               atomic_dec(&to_iah(wqe->ud_wr.ah)->refcount);
                        if (++qp->s_last >= qp->s_size)
                                qp->s_last = 0;
                }
index 4544d6f88ad77c7f7c69fd6e6d4a138188f493b3..e6b7556d522108951bf38ebc6750b991eb232285 100644 (file)
@@ -373,10 +373,11 @@ int qib_make_rc_req(struct qib_qp *qp)
                                qp->s_flags |= QIB_S_WAIT_SSN_CREDIT;
                                goto bail;
                        }
+
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / sizeof(u32);
                        wqe->lpsn = wqe->psn;
@@ -386,15 +387,15 @@ int qib_make_rc_req(struct qib_qp *qp)
                                len = pmtu;
                                break;
                        }
-                       if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
+                       if (wqe->rdma_wr.wr.opcode == IB_WR_RDMA_WRITE)
                                qp->s_state = OP(RDMA_WRITE_ONLY);
                        else {
-                               qp->s_state =
-                                       OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
+                               qp->s_state = OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
                                /* Immediate data comes after RETH */
-                               ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
+                               ohdr->u.rc.imm_data =
+                                       wqe->rdma_wr.wr.ex.imm_data;
                                hwords += 1;
-                               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+                               if (wqe->rdma_wr.wr.send_flags & IB_SEND_SOLICITED)
                                        bth0 |= IB_BTH_SOLICITED;
                        }
                        bth2 |= IB_BTH_REQ_ACK;
@@ -424,10 +425,11 @@ int qib_make_rc_req(struct qib_qp *qp)
                                        qp->s_next_psn += (len - 1) / pmtu;
                                wqe->lpsn = qp->s_next_psn++;
                        }
+
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        qp->s_state = OP(RDMA_READ_REQUEST);
                        hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
@@ -455,24 +457,24 @@ int qib_make_rc_req(struct qib_qp *qp)
                                        qp->s_lsn++;
                                wqe->lpsn = wqe->psn;
                        }
-                       if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+                       if (wqe->atomic_wr.wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
                                qp->s_state = OP(COMPARE_SWAP);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.swap);
+                                       wqe->atomic_wr.swap);
                                ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                        } else {
                                qp->s_state = OP(FETCH_ADD);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                                ohdr->u.atomic_eth.compare_data = 0;
                        }
                        ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr >> 32);
+                               wqe->atomic_wr.remote_addr >> 32);
                        ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr);
+                               wqe->atomic_wr.remote_addr);
                        ohdr->u.atomic_eth.rkey = cpu_to_be32(
-                               wqe->wr.wr.atomic.rkey);
+                               wqe->atomic_wr.rkey);
                        hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
                        ss = NULL;
                        len = 0;
@@ -597,9 +599,9 @@ int qib_make_rc_req(struct qib_qp *qp)
                 */
                len = ((qp->s_psn - wqe->psn) & QIB_PSN_MASK) * pmtu;
                ohdr->u.rc.reth.vaddr =
-                       cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len);
+                       cpu_to_be64(wqe->rdma_wr.remote_addr + len);
                ohdr->u.rc.reth.rkey =
-                       cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       cpu_to_be32(wqe->rdma_wr.rkey);
                ohdr->u.rc.reth.length = cpu_to_be32(wqe->length - len);
                qp->s_state = OP(RDMA_READ_REQUEST);
                hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
index 22e356ca8058af1511d8a2a4af4947bd2c0fc892..b1aa21bdd484486b50a1c6dd02d6945bacb8dffa 100644 (file)
@@ -459,8 +459,8 @@ again:
                if (wqe->length == 0)
                        break;
                if (unlikely(!qib_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
-                                         wqe->wr.wr.rdma.remote_addr,
-                                         wqe->wr.wr.rdma.rkey,
+                                         wqe->rdma_wr.remote_addr,
+                                         wqe->rdma_wr.rkey,
                                          IB_ACCESS_REMOTE_WRITE)))
                        goto acc_err;
                qp->r_sge.sg_list = NULL;
@@ -472,8 +472,8 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
                        goto inv_err;
                if (unlikely(!qib_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
-                                         wqe->wr.wr.rdma.remote_addr,
-                                         wqe->wr.wr.rdma.rkey,
+                                         wqe->rdma_wr.remote_addr,
+                                         wqe->rdma_wr.rkey,
                                          IB_ACCESS_REMOTE_READ)))
                        goto acc_err;
                release = 0;
@@ -490,18 +490,18 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
                if (unlikely(!qib_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
-                                         wqe->wr.wr.atomic.remote_addr,
-                                         wqe->wr.wr.atomic.rkey,
+                                         wqe->atomic_wr.remote_addr,
+                                         wqe->atomic_wr.rkey,
                                          IB_ACCESS_REMOTE_ATOMIC)))
                        goto acc_err;
                /* Perform atomic OP and save result. */
                maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
-               sdata = wqe->wr.wr.atomic.compare_add;
+               sdata = wqe->atomic_wr.compare_add;
                *(u64 *) sqp->s_sge.sge.vaddr =
-                       (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
+                       (wqe->atomic_wr.wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
                        (u64) atomic64_add_return(sdata, maddr) - sdata :
                        (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
-                                     sdata, wqe->wr.wr.atomic.swap);
+                                     sdata, wqe->atomic_wr.swap);
                qib_put_mr(qp->r_sge.sge.mr);
                qp->r_sge.num_sge = 0;
                goto send_comp;
@@ -785,7 +785,7 @@ void qib_send_complete(struct qib_qp *qp, struct qib_swqe *wqe,
        if (qp->ibqp.qp_type == IB_QPT_UD ||
            qp->ibqp.qp_type == IB_QPT_SMI ||
            qp->ibqp.qp_type == IB_QPT_GSI)
-               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+               atomic_dec(&to_iah(wqe->ud_wr.ah)->refcount);
 
        /* See ch. 11.2.4.1 and 10.7.3.1 */
        if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
index aa3a8035bb68f257a0400bbedd8655e93584c7cb..06a564589c35d1212065cae4e8c77c4ec3647b1c 100644 (file)
@@ -129,9 +129,9 @@ int qib_make_uc_req(struct qib_qp *qp)
                case IB_WR_RDMA_WRITE:
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / 4;
                        if (len > pmtu) {
index 26243b722b5e979c1324471b6e17871d3ef22540..59193f67ea78780fc4be1dd367814f1634f849ac 100644 (file)
@@ -59,7 +59,7 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
        u32 length;
        enum ib_qp_type sqptype, dqptype;
 
-       qp = qib_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn);
+       qp = qib_lookup_qpn(ibp, swqe->ud_wr.remote_qpn);
        if (!qp) {
                ibp->n_pkt_drops++;
                return;
@@ -76,7 +76,7 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
                goto drop;
        }
 
-       ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(swqe->ud_wr.ah)->attr;
        ppd = ppd_from_ibp(ibp);
 
        if (qp->ibqp.qp_num > 1) {
@@ -106,8 +106,8 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
        if (qp->ibqp.qp_num) {
                u32 qkey;
 
-               qkey = (int)swqe->wr.wr.ud.remote_qkey < 0 ?
-                       sqp->qkey : swqe->wr.wr.ud.remote_qkey;
+               qkey = (int)swqe->ud_wr.remote_qkey < 0 ?
+                       sqp->qkey : swqe->ud_wr.remote_qkey;
                if (unlikely(qkey != qp->qkey)) {
                        u16 lid;
 
@@ -210,7 +210,7 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
        wc.qp = &qp->ibqp;
        wc.src_qp = sqp->ibqp.qp_num;
        wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ?
-               swqe->wr.wr.ud.pkey_index : 0;
+               swqe->ud_wr.pkey_index : 0;
        wc.slid = ppd->lid | (ah_attr->src_path_bits & ((1 << ppd->lmc) - 1));
        wc.sl = ah_attr->sl;
        wc.dlid_path_bits = ah_attr->dlid & ((1 << ppd->lmc) - 1);
@@ -277,7 +277,7 @@ int qib_make_ud_req(struct qib_qp *qp)
        /* Construct the header. */
        ibp = to_iport(qp->ibqp.device, qp->port_num);
        ppd = ppd_from_ibp(ibp);
-       ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(wqe->ud_wr.ah)->attr;
        if (ah_attr->dlid >= QIB_MULTICAST_LID_BASE) {
                if (ah_attr->dlid != QIB_PERMISSIVE_LID)
                        this_cpu_inc(ibp->pmastats->n_multicast_xmit);
@@ -363,7 +363,7 @@ int qib_make_ud_req(struct qib_qp *qp)
        bth0 |= extra_bytes << 20;
        bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? QIB_DEFAULT_P_KEY :
                qib_get_pkey(ibp, qp->ibqp.qp_type == IB_QPT_GSI ?
-                            wqe->wr.wr.ud.pkey_index : qp->s_pkey_index);
+                            wqe->ud_wr.pkey_index : qp->s_pkey_index);
        ohdr->bth[0] = cpu_to_be32(bth0);
        /*
         * Use the multicast QP if the destination LID is a multicast LID.
@@ -371,14 +371,14 @@ int qib_make_ud_req(struct qib_qp *qp)
        ohdr->bth[1] = ah_attr->dlid >= QIB_MULTICAST_LID_BASE &&
                ah_attr->dlid != QIB_PERMISSIVE_LID ?
                cpu_to_be32(QIB_MULTICAST_QPN) :
-               cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
+               cpu_to_be32(wqe->ud_wr.remote_qpn);
        ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & QIB_PSN_MASK);
        /*
         * Qkeys with the high order bit set mean use the
         * qkey from the QP context instead of the WR (see 10.2.5).
         */
-       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
-                                        qp->qkey : wqe->wr.wr.ud.remote_qkey);
+       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
+                                        qp->qkey : wqe->ud_wr.remote_qkey);
        ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
 
 done:
index 3dcc4985b60ff861d5d7e2b5c9a8a9c780bccf2d..de6cb6fcda8df3d5a1060aceecf20c832ba81ace 100644 (file)
@@ -362,8 +362,8 @@ static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr,
         * undefined operations.
         * Make sure buffer is large enough to hold the result for atomics.
         */
-       if (wr->opcode == IB_WR_FAST_REG_MR) {
-               if (qib_fast_reg_mr(qp, wr))
+       if (wr->opcode == IB_WR_REG_MR) {
+               if (qib_reg_mr(qp, reg_wr(wr)))
                        goto bail_inval;
        } else if (qp->ibqp.qp_type == IB_QPT_UC) {
                if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
@@ -374,7 +374,7 @@ static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr,
                    wr->opcode != IB_WR_SEND_WITH_IMM)
                        goto bail_inval;
                /* Check UD destination address PD */
-               if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
                        goto bail_inval;
        } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
                goto bail_inval;
@@ -397,7 +397,23 @@ static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr,
        rkt = &to_idev(qp->ibqp.device)->lk_table;
        pd = to_ipd(qp->ibqp.pd);
        wqe = get_swqe_ptr(qp, qp->s_head);
-       wqe->wr = *wr;
+
+       if (qp->ibqp.qp_type != IB_QPT_UC &&
+           qp->ibqp.qp_type != IB_QPT_RC)
+               memcpy(&wqe->ud_wr, ud_wr(wr), sizeof(wqe->ud_wr));
+       else if (wr->opcode == IB_WR_REG_MR)
+               memcpy(&wqe->reg_wr, reg_wr(wr),
+                       sizeof(wqe->reg_wr));
+       else if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                wr->opcode == IB_WR_RDMA_WRITE ||
+                wr->opcode == IB_WR_RDMA_READ)
+               memcpy(&wqe->rdma_wr, rdma_wr(wr), sizeof(wqe->rdma_wr));
+       else if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+               memcpy(&wqe->atomic_wr, atomic_wr(wr), sizeof(wqe->atomic_wr));
+       else
+               memcpy(&wqe->wr, wr, sizeof(wqe->wr));
+
        wqe->length = 0;
        j = 0;
        if (wr->num_sge) {
@@ -426,7 +442,7 @@ static int qib_post_one_send(struct qib_qp *qp, struct ib_send_wr *wr,
                                  qp->port_num - 1)->ibmtu)
                goto bail_inval_free;
        else
-               atomic_inc(&to_iah(wr->wr.ud.ah)->refcount);
+               atomic_inc(&to_iah(ud_wr(wr)->ah)->refcount);
        wqe->ssn = qp->s_ssn++;
        qp->s_head = next;
 
@@ -2244,8 +2260,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
        ibdev->reg_user_mr = qib_reg_user_mr;
        ibdev->dereg_mr = qib_dereg_mr;
        ibdev->alloc_mr = qib_alloc_mr;
-       ibdev->alloc_fast_reg_page_list = qib_alloc_fast_reg_page_list;
-       ibdev->free_fast_reg_page_list = qib_free_fast_reg_page_list;
+       ibdev->map_mr_sg = qib_map_mr_sg;
        ibdev->alloc_fmr = qib_alloc_fmr;
        ibdev->map_phys_fmr = qib_map_phys_fmr;
        ibdev->unmap_fmr = qib_unmap_fmr;
index a08df70e85038a220a0dce5a3ccc30f9d165bcd5..2baf5ad251ed24a02682051058e6d1a406419e04 100644 (file)
@@ -330,6 +330,8 @@ struct qib_mr {
        struct ib_mr ibmr;
        struct ib_umem *umem;
        struct qib_mregion mr;  /* must be last */
+       u64 *pages;
+       u32 npages;
 };
 
 /*
@@ -338,7 +340,13 @@ struct qib_mr {
  * in qp->s_max_sge.
  */
 struct qib_swqe {
-       struct ib_send_wr wr;   /* don't use wr.sg_list */
+       union {
+               struct ib_send_wr wr;   /* don't use wr.sg_list */
+               struct ib_ud_wr ud_wr;
+               struct ib_reg_wr reg_wr;
+               struct ib_rdma_wr rdma_wr;
+               struct ib_atomic_wr atomic_wr;
+       };
        u32 psn;                /* first packet sequence number */
        u32 lpsn;               /* last packet sequence number */
        u32 ssn;                /* send sequence number */
@@ -1038,12 +1046,11 @@ struct ib_mr *qib_alloc_mr(struct ib_pd *pd,
                           enum ib_mr_type mr_type,
                           u32 max_entries);
 
-struct ib_fast_reg_page_list *qib_alloc_fast_reg_page_list(
-                               struct ib_device *ibdev, int page_list_len);
-
-void qib_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl);
+int qib_map_mr_sg(struct ib_mr *ibmr,
+                 struct scatterlist *sg,
+                 int sg_nents);
 
-int qib_fast_reg_mr(struct qib_qp *qp, struct ib_send_wr *wr);
+int qib_reg_mr(struct qib_qp *qp, struct ib_reg_wr *wr);
 
 struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
                             struct ib_fmr_attr *fmr_attr);
index 0c15bd885035ee5fe5110e1317cafe09e762fe07..565c881a44ba069f69f64da6b1a215fdc3bf7f19 100644 (file)
@@ -343,16 +343,15 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
        netdev = pci_get_drvdata(dev);
 
        us_ibdev = (struct usnic_ib_dev *)ib_alloc_device(sizeof(*us_ibdev));
-       if (IS_ERR_OR_NULL(us_ibdev)) {
+       if (!us_ibdev) {
                usnic_err("Device %s context alloc failed\n",
                                netdev_name(pci_get_drvdata(dev)));
-               return ERR_PTR(us_ibdev ? PTR_ERR(us_ibdev) : -EFAULT);
+               return ERR_PTR(-EFAULT);
        }
 
        us_ibdev->ufdev = usnic_fwd_dev_alloc(dev);
-       if (IS_ERR_OR_NULL(us_ibdev->ufdev)) {
-               usnic_err("Failed to alloc ufdev for %s with err %ld\n",
-                               pci_name(dev), PTR_ERR(us_ibdev->ufdev));
+       if (!us_ibdev->ufdev) {
+               usnic_err("Failed to alloc ufdev for %s\n", pci_name(dev));
                goto err_dealloc;
        }
 
index 85dc3f989ff72aa565c85efb4d07fdc7772d3c93..fcea3a24d3eb310ef0ee3c573a3ef9e161c8e809 100644 (file)
@@ -236,8 +236,8 @@ create_roce_custom_flow(struct usnic_ib_qp_grp *qp_grp,
 
        /* Create Flow Handle */
        qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
-       if (IS_ERR_OR_NULL(qp_flow)) {
-               err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
+       if (!qp_flow) {
+               err = -ENOMEM;
                goto out_dealloc_flow;
        }
        qp_flow->flow = flow;
@@ -311,8 +311,8 @@ create_udp_flow(struct usnic_ib_qp_grp *qp_grp,
 
        /* Create qp_flow */
        qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
-       if (IS_ERR_OR_NULL(qp_flow)) {
-               err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
+       if (!qp_flow) {
+               err = -ENOMEM;
                goto out_dealloc_flow;
        }
        qp_flow->flow = flow;
index edc5b8565d6d9eb5ba6e22e1baefd21d53986b5f..3ede103097547d4355646d322b5570ebb421d2ec 100644 (file)
@@ -360,7 +360,7 @@ struct ipoib_dev_priv {
        unsigned             tx_head;
        unsigned             tx_tail;
        struct ib_sge        tx_sge[MAX_SKB_FRAGS + 1];
-       struct ib_send_wr    tx_wr;
+       struct ib_ud_wr      tx_wr;
        unsigned             tx_outstanding;
        struct ib_wc         send_wc[MAX_SEND_CQE];
 
@@ -528,7 +528,7 @@ static inline void ipoib_build_sge(struct ipoib_dev_priv *priv,
                priv->tx_sge[i + off].addr = mapping[i + off];
                priv->tx_sge[i + off].length = skb_frag_size(&frags[i]);
        }
-       priv->tx_wr.num_sge          = nr_frags + off;
+       priv->tx_wr.wr.num_sge       = nr_frags + off;
 }
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
index c78dc1638030093298c28e13605c86845ce1fcfc..3ae9726efb9837512a62214705bf5e8e9561a02c 100644 (file)
@@ -700,9 +700,9 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 
        ipoib_build_sge(priv, tx_req);
 
-       priv->tx_wr.wr_id       = wr_id | IPOIB_OP_CM;
+       priv->tx_wr.wr.wr_id    = wr_id | IPOIB_OP_CM;
 
-       return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
+       return ib_post_send(tx->qp, &priv->tx_wr.wr, &bad_wr);
 }
 
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
index d266667ca9b82273dd4b7abb4856f69b29f65174..5ea0c14070d1f2d8af36a05c15206c63f406b97d 100644 (file)
@@ -518,19 +518,19 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 
        ipoib_build_sge(priv, tx_req);
 
-       priv->tx_wr.wr_id            = wr_id;
-       priv->tx_wr.wr.ud.remote_qpn = qpn;
-       priv->tx_wr.wr.ud.ah         = address;
+       priv->tx_wr.wr.wr_id    = wr_id;
+       priv->tx_wr.remote_qpn  = qpn;
+       priv->tx_wr.ah          = address;
 
        if (head) {
-               priv->tx_wr.wr.ud.mss    = skb_shinfo(skb)->gso_size;
-               priv->tx_wr.wr.ud.header = head;
-               priv->tx_wr.wr.ud.hlen   = hlen;
-               priv->tx_wr.opcode       = IB_WR_LSO;
+               priv->tx_wr.mss         = skb_shinfo(skb)->gso_size;
+               priv->tx_wr.header      = head;
+               priv->tx_wr.hlen        = hlen;
+               priv->tx_wr.wr.opcode   = IB_WR_LSO;
        } else
-               priv->tx_wr.opcode       = IB_WR_SEND;
+               priv->tx_wr.wr.opcode   = IB_WR_SEND;
 
-       return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
+       return ib_post_send(priv->qp, &priv->tx_wr.wr, &bad_wr);
 }
 
 void ipoib_send(struct net_device *dev, struct sk_buff *skb,
@@ -583,9 +583,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
        }
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
-               priv->tx_wr.send_flags |= IB_SEND_IP_CSUM;
+               priv->tx_wr.wr.send_flags |= IB_SEND_IP_CSUM;
        else
-               priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
+               priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
 
        if (++priv->tx_outstanding == ipoib_sendq_size) {
                ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
index babba05d7a0eb707f472d7de3cb06843a0844eff..7d3281866ffcd520d4bca543a9ad0544f2ec159f 100644 (file)
@@ -461,7 +461,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
                netdev_update_features(dev);
                dev_set_mtu(dev, ipoib_cm_max_mtu(dev));
                rtnl_unlock();
-               priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
+               priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
 
                ipoib_flush_paths(dev);
                rtnl_lock();
@@ -1860,7 +1860,7 @@ static struct net_device *ipoib_add_port(const char *format,
        priv->dev->broadcast[8] = priv->pkey >> 8;
        priv->dev->broadcast[9] = priv->pkey & 0xff;
 
-       result = ib_query_gid(hca, port, 0, &priv->local_gid);
+       result = ib_query_gid(hca, port, 0, &priv->local_gid, NULL);
        if (result) {
                printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n",
                       hca->name, port, result);
index d750a86042f3d8da0736c23a52f41737b329c37d..f357ca67a41cd859b2ff5e704621f72813b91fa8 100644 (file)
@@ -245,7 +245,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 
                priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);
                spin_unlock_irq(&priv->lock);
-               priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
+               priv->tx_wr.remote_qkey = priv->qkey;
                set_qkey = 1;
        }
 
@@ -561,7 +561,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
        }
        priv->local_lid = port_attr.lid;
 
-       if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid))
+       if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid, NULL))
                ipoib_warn(priv, "ib_query_gid() failed\n");
        else
                memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
index 78845b6e8b812737477ce68dcbc6c1712477d23d..d48c5bae78774663c17e72ed1e4c87475e1005ad 100644 (file)
@@ -221,9 +221,9 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
        for (i = 0; i < MAX_SKB_FRAGS + 1; ++i)
                priv->tx_sge[i].lkey = priv->pd->local_dma_lkey;
 
-       priv->tx_wr.opcode      = IB_WR_SEND;
-       priv->tx_wr.sg_list     = priv->tx_sge;
-       priv->tx_wr.send_flags  = IB_SEND_SIGNALED;
+       priv->tx_wr.wr.opcode           = IB_WR_SEND;
+       priv->tx_wr.wr.sg_list          = priv->tx_sge;
+       priv->tx_wr.wr.send_flags       = IB_SEND_SIGNALED;
 
        priv->rx_sge[0].lkey = priv->pd->local_dma_lkey;
 
index f58ff96b6cbb9778153b4ab79794f8a206fa9343..9080161e01af1614afa5796a134d7fd890a1be45 100644 (file)
@@ -111,7 +111,7 @@ module_param_named(pi_guard, iser_pi_guard, int, S_IRUGO);
 MODULE_PARM_DESC(pi_guard, "T10-PI guard_type [deprecated]");
 
 /*
- * iscsi_iser_recv() - Process a successfull recv completion
+ * iscsi_iser_recv() - Process a successful recv completion
  * @conn:         iscsi connection
  * @hdr:          iscsi header
  * @rx_data:      buffer containing receive data payload
@@ -126,7 +126,6 @@ iscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 {
        int rc = 0;
        int datalen;
-       int ahslen;
 
        /* verify PDU length */
        datalen = ntoh24(hdr->dlength);
@@ -141,9 +140,6 @@ iscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                iser_dbg("aligned datalen (%d) hdr, %d (IB)\n",
                        datalen, rx_data_len);
 
-       /* read AHS */
-       ahslen = hdr->hlength * 4;
-
        rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
        if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
                goto error;
@@ -766,9 +762,7 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
        stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
        stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
        stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
-       stats->custom_length = 1;
-       strcpy(stats->custom[0].desc, "fmr_unalign_cnt");
-       stats->custom[0].value = conn->fmr_unalign_cnt;
+       stats->custom_length = 0;
 }
 
 static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep,
@@ -973,6 +967,13 @@ static umode_t iser_attr_is_visible(int param_type, int param)
        return 0;
 }
 
+static int iscsi_iser_slave_alloc(struct scsi_device *sdev)
+{
+       blk_queue_virt_boundary(sdev->request_queue, ~MASK_4K);
+
+       return 0;
+}
+
 static struct scsi_host_template iscsi_iser_sht = {
        .module                 = THIS_MODULE,
        .name                   = "iSCSI Initiator over iSER",
@@ -985,7 +986,8 @@ static struct scsi_host_template iscsi_iser_sht = {
        .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
        .target_alloc           = iscsi_target_alloc,
-       .use_clustering         = DISABLE_CLUSTERING,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .slave_alloc            = iscsi_iser_slave_alloc,
        .proc_name              = "iscsi_iser",
        .this_id                = -1,
        .track_queue_depth      = 1,
index a5edd6ede692c7be3d1c6da2f355b062cea9e43e..8a5998e6a407997906e45864ac9799fdac468084 100644 (file)
@@ -227,18 +227,13 @@ enum iser_data_dir {
  * @size:         num entries of this sg
  * @data_len:     total beffer byte len
  * @dma_nents:    returned by dma_map_sg
- * @orig_sg:      pointer to the original sg list (in case
- *                we used a copy)
- * @orig_size:    num entris of orig sg list
  */
 struct iser_data_buf {
        struct scatterlist *sg;
-       unsigned int       size;
+       int                size;
        unsigned long      data_len;
        unsigned int       dma_nents;
-       struct scatterlist *orig_sg;
-       unsigned int       orig_size;
-  };
+};
 
 /* fwd declarations */
 struct iser_device;
@@ -300,7 +295,11 @@ struct iser_tx_desc {
        int                          num_sge;
        bool                         mapped;
        u8                           wr_idx;
-       struct ib_send_wr            wrs[ISER_MAX_WRS];
+       union iser_wr {
+               struct ib_send_wr               send;
+               struct ib_reg_wr                fast_reg;
+               struct ib_sig_handover_wr       sig;
+       } wrs[ISER_MAX_WRS];
        struct iser_mem_reg          data_reg;
        struct iser_mem_reg          prot_reg;
        struct ib_sig_attrs          sig_attrs;
@@ -413,7 +412,6 @@ struct iser_device {
  *
  * @mr:         memory region
  * @fmr_pool:   pool of fmrs
- * @frpl:       fast reg page list used by frwrs
  * @page_vec:   fast reg page list used by fmr pool
  * @mr_valid:   is mr valid indicator
  */
@@ -422,10 +420,7 @@ struct iser_reg_resources {
                struct ib_mr             *mr;
                struct ib_fmr_pool       *fmr_pool;
        };
-       union {
-               struct ib_fast_reg_page_list     *frpl;
-               struct iser_page_vec             *page_vec;
-       };
+       struct iser_page_vec             *page_vec;
        u8                                mr_valid:1;
 };
 
@@ -712,11 +707,11 @@ iser_reg_desc_put_fmr(struct ib_conn *ib_conn,
 static inline struct ib_send_wr *
 iser_tx_next_wr(struct iser_tx_desc *tx_desc)
 {
-       struct ib_send_wr *cur_wr = &tx_desc->wrs[tx_desc->wr_idx];
+       struct ib_send_wr *cur_wr = &tx_desc->wrs[tx_desc->wr_idx].send;
        struct ib_send_wr *last_wr;
 
        if (tx_desc->wr_idx) {
-               last_wr = &tx_desc->wrs[tx_desc->wr_idx - 1];
+               last_wr = &tx_desc->wrs[tx_desc->wr_idx - 1].send;
                last_wr->next = cur_wr;
        }
        tx_desc->wr_idx++;
index d511879d8cdfc862765f871b0876b43307e3b7c7..ffd00c42072959ed6747b5094e159cb34532675f 100644 (file)
@@ -661,48 +661,14 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
 
 void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
 {
-       int is_rdma_data_aligned = 1;
-       int is_rdma_prot_aligned = 1;
        int prot_count = scsi_prot_sg_count(iser_task->sc);
 
-       /* if we were reading, copy back to unaligned sglist,
-        * anyway dma_unmap and free the copy
-        */
-       if (iser_task->data[ISER_DIR_IN].orig_sg) {
-               is_rdma_data_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_task,
-                                               &iser_task->data[ISER_DIR_IN],
-                                               ISER_DIR_IN);
-       }
-
-       if (iser_task->data[ISER_DIR_OUT].orig_sg) {
-               is_rdma_data_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_task,
-                                               &iser_task->data[ISER_DIR_OUT],
-                                               ISER_DIR_OUT);
-       }
-
-       if (iser_task->prot[ISER_DIR_IN].orig_sg) {
-               is_rdma_prot_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_task,
-                                               &iser_task->prot[ISER_DIR_IN],
-                                               ISER_DIR_IN);
-       }
-
-       if (iser_task->prot[ISER_DIR_OUT].orig_sg) {
-               is_rdma_prot_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_task,
-                                               &iser_task->prot[ISER_DIR_OUT],
-                                               ISER_DIR_OUT);
-       }
-
        if (iser_task->dir[ISER_DIR_IN]) {
                iser_unreg_rdma_mem(iser_task, ISER_DIR_IN);
-               if (is_rdma_data_aligned)
-                       iser_dma_unmap_task_data(iser_task,
-                                                &iser_task->data[ISER_DIR_IN],
-                                                DMA_FROM_DEVICE);
-               if (prot_count && is_rdma_prot_aligned)
+               iser_dma_unmap_task_data(iser_task,
+                                        &iser_task->data[ISER_DIR_IN],
+                                        DMA_FROM_DEVICE);
+               if (prot_count)
                        iser_dma_unmap_task_data(iser_task,
                                                 &iser_task->prot[ISER_DIR_IN],
                                                 DMA_FROM_DEVICE);
@@ -710,11 +676,10 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
 
        if (iser_task->dir[ISER_DIR_OUT]) {
                iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT);
-               if (is_rdma_data_aligned)
-                       iser_dma_unmap_task_data(iser_task,
-                                                &iser_task->data[ISER_DIR_OUT],
-                                                DMA_TO_DEVICE);
-               if (prot_count && is_rdma_prot_aligned)
+               iser_dma_unmap_task_data(iser_task,
+                                        &iser_task->data[ISER_DIR_OUT],
+                                        DMA_TO_DEVICE);
+               if (prot_count)
                        iser_dma_unmap_task_data(iser_task,
                                                 &iser_task->prot[ISER_DIR_OUT],
                                                 DMA_TO_DEVICE);
index 4c46d67d37a13100b60c6daa0a0b01b8f6855608..ea765fb9664d36759ff1a90d11272c1bc13ca457 100644 (file)
@@ -88,113 +88,6 @@ int iser_assign_reg_ops(struct iser_device *device)
        return 0;
 }
 
-static void
-iser_free_bounce_sg(struct iser_data_buf *data)
-{
-       struct scatterlist *sg;
-       int count;
-
-       for_each_sg(data->sg, sg, data->size, count)
-               __free_page(sg_page(sg));
-
-       kfree(data->sg);
-
-       data->sg = data->orig_sg;
-       data->size = data->orig_size;
-       data->orig_sg = NULL;
-       data->orig_size = 0;
-}
-
-static int
-iser_alloc_bounce_sg(struct iser_data_buf *data)
-{
-       struct scatterlist *sg;
-       struct page *page;
-       unsigned long length = data->data_len;
-       int i = 0, nents = DIV_ROUND_UP(length, PAGE_SIZE);
-
-       sg = kcalloc(nents, sizeof(*sg), GFP_ATOMIC);
-       if (!sg)
-               goto err;
-
-       sg_init_table(sg, nents);
-       while (length) {
-               u32 page_len = min_t(u32, length, PAGE_SIZE);
-
-               page = alloc_page(GFP_ATOMIC);
-               if (!page)
-                       goto err;
-
-               sg_set_page(&sg[i], page, page_len, 0);
-               length -= page_len;
-               i++;
-       }
-
-       data->orig_sg = data->sg;
-       data->orig_size = data->size;
-       data->sg = sg;
-       data->size = nents;
-
-       return 0;
-
-err:
-       for (; i > 0; i--)
-               __free_page(sg_page(&sg[i - 1]));
-       kfree(sg);
-
-       return -ENOMEM;
-}
-
-static void
-iser_copy_bounce(struct iser_data_buf *data, bool to_buffer)
-{
-       struct scatterlist *osg, *bsg = data->sg;
-       void *oaddr, *baddr;
-       unsigned int left = data->data_len;
-       unsigned int bsg_off = 0;
-       int i;
-
-       for_each_sg(data->orig_sg, osg, data->orig_size, i) {
-               unsigned int copy_len, osg_off = 0;
-
-               oaddr = kmap_atomic(sg_page(osg)) + osg->offset;
-               copy_len = min(left, osg->length);
-               while (copy_len) {
-                       unsigned int len = min(copy_len, bsg->length - bsg_off);
-
-                       baddr = kmap_atomic(sg_page(bsg)) + bsg->offset;
-                       if (to_buffer)
-                               memcpy(baddr + bsg_off, oaddr + osg_off, len);
-                       else
-                               memcpy(oaddr + osg_off, baddr + bsg_off, len);
-
-                       kunmap_atomic(baddr - bsg->offset);
-                       osg_off += len;
-                       bsg_off += len;
-                       copy_len -= len;
-
-                       if (bsg_off >= bsg->length) {
-                               bsg = sg_next(bsg);
-                               bsg_off = 0;
-                       }
-               }
-               kunmap_atomic(oaddr - osg->offset);
-               left -= osg_off;
-       }
-}
-
-static inline void
-iser_copy_from_bounce(struct iser_data_buf *data)
-{
-       iser_copy_bounce(data, false);
-}
-
-static inline void
-iser_copy_to_bounce(struct iser_data_buf *data)
-{
-       iser_copy_bounce(data, true);
-}
-
 struct iser_fr_desc *
 iser_reg_desc_get_fr(struct ib_conn *ib_conn)
 {
@@ -238,62 +131,6 @@ iser_reg_desc_put_fmr(struct ib_conn *ib_conn,
 {
 }
 
-/**
- * iser_start_rdma_unaligned_sg
- */
-static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
-                                       struct iser_data_buf *data,
-                                       enum iser_data_dir cmd_dir)
-{
-       struct ib_device *dev = iser_task->iser_conn->ib_conn.device->ib_device;
-       int rc;
-
-       rc = iser_alloc_bounce_sg(data);
-       if (rc) {
-               iser_err("Failed to allocate bounce for data len %lu\n",
-                        data->data_len);
-               return rc;
-       }
-
-       if (cmd_dir == ISER_DIR_OUT)
-               iser_copy_to_bounce(data);
-
-       data->dma_nents = ib_dma_map_sg(dev, data->sg, data->size,
-                                       (cmd_dir == ISER_DIR_OUT) ?
-                                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
-       if (!data->dma_nents) {
-               iser_err("Got dma_nents %d, something went wrong...\n",
-                        data->dma_nents);
-               rc = -ENOMEM;
-               goto err;
-       }
-
-       return 0;
-err:
-       iser_free_bounce_sg(data);
-       return rc;
-}
-
-/**
- * iser_finalize_rdma_unaligned_sg
- */
-
-void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
-                                    struct iser_data_buf *data,
-                                    enum iser_data_dir cmd_dir)
-{
-       struct ib_device *dev = iser_task->iser_conn->ib_conn.device->ib_device;
-
-       ib_dma_unmap_sg(dev, data->sg, data->size,
-                       (cmd_dir == ISER_DIR_OUT) ?
-                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-       if (cmd_dir == ISER_DIR_IN)
-               iser_copy_from_bounce(data);
-
-       iser_free_bounce_sg(data);
-}
-
 #define IS_4K_ALIGNED(addr)    ((((unsigned long)addr) & ~MASK_4K) == 0)
 
 /**
@@ -355,64 +192,6 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
        return cur_page;
 }
 
-
-/**
- * iser_data_buf_aligned_len - Tries to determine the maximal correctly aligned
- * for RDMA sub-list of a scatter-gather list of memory buffers, and  returns
- * the number of entries which are aligned correctly. Supports the case where
- * consecutive SG elements are actually fragments of the same physcial page.
- */
-static int iser_data_buf_aligned_len(struct iser_data_buf *data,
-                                    struct ib_device *ibdev,
-                                    unsigned sg_tablesize)
-{
-       struct scatterlist *sg, *sgl, *next_sg = NULL;
-       u64 start_addr, end_addr;
-       int i, ret_len, start_check = 0;
-
-       if (data->dma_nents == 1)
-               return 1;
-
-       sgl = data->sg;
-       start_addr  = ib_sg_dma_address(ibdev, sgl);
-
-       if (unlikely(sgl[0].offset &&
-                    data->data_len >= sg_tablesize * PAGE_SIZE)) {
-               iser_dbg("can't register length %lx with offset %x "
-                        "fall to bounce buffer\n", data->data_len,
-                        sgl[0].offset);
-               return 0;
-       }
-
-       for_each_sg(sgl, sg, data->dma_nents, i) {
-               if (start_check && !IS_4K_ALIGNED(start_addr))
-                       break;
-
-               next_sg = sg_next(sg);
-               if (!next_sg)
-                       break;
-
-               end_addr    = start_addr + ib_sg_dma_len(ibdev, sg);
-               start_addr  = ib_sg_dma_address(ibdev, next_sg);
-
-               if (end_addr == start_addr) {
-                       start_check = 0;
-                       continue;
-               } else
-                       start_check = 1;
-
-               if (!IS_4K_ALIGNED(end_addr))
-                       break;
-       }
-       ret_len = (next_sg) ? i : i+1;
-
-       if (unlikely(ret_len != data->dma_nents))
-               iser_warn("rdma alignment violation (%d/%d aligned)\n",
-                         ret_len, data->dma_nents);
-
-       return ret_len;
-}
-
 static void iser_data_buf_dump(struct iser_data_buf *data,
                               struct ib_device *ibdev)
 {
@@ -483,31 +262,6 @@ iser_reg_dma(struct iser_device *device, struct iser_data_buf *mem,
        return 0;
 }
 
-static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
-                             struct iser_data_buf *mem,
-                             enum iser_data_dir cmd_dir)
-{
-       struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn;
-       struct iser_device *device = iser_task->iser_conn->ib_conn.device;
-
-       iscsi_conn->fmr_unalign_cnt++;
-
-       if (iser_debug_level > 0)
-               iser_data_buf_dump(mem, device->ib_device);
-
-       /* unmap the command data before accessing it */
-       iser_dma_unmap_task_data(iser_task, mem,
-                                (cmd_dir == ISER_DIR_OUT) ?
-                                DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-       /* allocate copy buf, if we are writing, copy the */
-       /* unaligned scatterlist, dma map the copy        */
-       if (iser_start_rdma_unaligned_sg(iser_task, mem, cmd_dir) != 0)
-               return -ENOMEM;
-
-       return 0;
-}
-
 /**
  * iser_reg_page_vec - Register physical memory
  *
@@ -683,7 +437,7 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
 {
        struct iser_tx_desc *tx_desc = &iser_task->desc;
        struct ib_sig_attrs *sig_attrs = &tx_desc->sig_attrs;
-       struct ib_send_wr *wr;
+       struct ib_sig_handover_wr *wr;
        int ret;
 
        memset(sig_attrs, 0, sizeof(*sig_attrs));
@@ -693,26 +447,24 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
 
        iser_set_prot_checks(iser_task->sc, &sig_attrs->check_mask);
 
-       if (!pi_ctx->sig_mr_valid) {
-               wr = iser_tx_next_wr(tx_desc);
-               iser_inv_rkey(wr, pi_ctx->sig_mr);
-       }
-
-       wr = iser_tx_next_wr(tx_desc);
-       wr->opcode = IB_WR_REG_SIG_MR;
-       wr->wr_id = ISER_FASTREG_LI_WRID;
-       wr->sg_list = &data_reg->sge;
-       wr->num_sge = 1;
-       wr->send_flags = 0;
-       wr->wr.sig_handover.sig_attrs = sig_attrs;
-       wr->wr.sig_handover.sig_mr = pi_ctx->sig_mr;
+       if (!pi_ctx->sig_mr_valid)
+               iser_inv_rkey(iser_tx_next_wr(tx_desc), pi_ctx->sig_mr);
+
+       wr = sig_handover_wr(iser_tx_next_wr(tx_desc));
+       wr->wr.opcode = IB_WR_REG_SIG_MR;
+       wr->wr.wr_id = ISER_FASTREG_LI_WRID;
+       wr->wr.sg_list = &data_reg->sge;
+       wr->wr.num_sge = 1;
+       wr->wr.send_flags = 0;
+       wr->sig_attrs = sig_attrs;
+       wr->sig_mr = pi_ctx->sig_mr;
        if (scsi_prot_sg_count(iser_task->sc))
-               wr->wr.sig_handover.prot = &prot_reg->sge;
+               wr->prot = &prot_reg->sge;
        else
-               wr->wr.sig_handover.prot = NULL;
-       wr->wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE |
-                                          IB_ACCESS_REMOTE_READ |
-                                          IB_ACCESS_REMOTE_WRITE;
+               wr->prot = NULL;
+       wr->access_flags = IB_ACCESS_LOCAL_WRITE |
+                          IB_ACCESS_REMOTE_READ |
+                          IB_ACCESS_REMOTE_WRITE;
        pi_ctx->sig_mr_valid = 0;
 
        sig_reg->sge.lkey = pi_ctx->sig_mr->lkey;
@@ -720,7 +472,7 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
        sig_reg->sge.addr = 0;
        sig_reg->sge.length = scsi_transfer_length(iser_task->sc);
 
-       iser_dbg("sig reg: lkey: 0x%x, rkey: 0x%x, addr: 0x%llx, length: %u\n",
+       iser_dbg("lkey=0x%x rkey=0x%x addr=0x%llx length=%u\n",
                 sig_reg->sge.lkey, sig_reg->rkey, sig_reg->sge.addr,
                 sig_reg->sge.length);
 err:
@@ -732,69 +484,41 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
                            struct iser_reg_resources *rsc,
                            struct iser_mem_reg *reg)
 {
-       struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn;
-       struct iser_device *device = ib_conn->device;
-       struct ib_mr *mr = rsc->mr;
-       struct ib_fast_reg_page_list *frpl = rsc->frpl;
        struct iser_tx_desc *tx_desc = &iser_task->desc;
-       struct ib_send_wr *wr;
-       int offset, size, plen;
+       struct ib_mr *mr = rsc->mr;
+       struct ib_reg_wr *wr;
+       int n;
 
-       plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list,
-                                  &offset, &size);
-       if (plen * SIZE_4K < size) {
-               iser_err("fast reg page_list too short to hold this SG\n");
-               return -EINVAL;
-       }
+       if (!rsc->mr_valid)
+               iser_inv_rkey(iser_tx_next_wr(tx_desc), mr);
 
-       if (!rsc->mr_valid) {
-               wr = iser_tx_next_wr(tx_desc);
-               iser_inv_rkey(wr, mr);
+       n = ib_map_mr_sg(mr, mem->sg, mem->size, SIZE_4K);
+       if (unlikely(n != mem->size)) {
+               iser_err("failed to map sg (%d/%d)\n",
+                        n, mem->size);
+               return n < 0 ? n : -EINVAL;
        }
 
-       wr = iser_tx_next_wr(tx_desc);
-       wr->opcode = IB_WR_FAST_REG_MR;
-       wr->wr_id = ISER_FASTREG_LI_WRID;
-       wr->send_flags = 0;
-       wr->wr.fast_reg.iova_start = frpl->page_list[0] + offset;
-       wr->wr.fast_reg.page_list = frpl;
-       wr->wr.fast_reg.page_list_len = plen;
-       wr->wr.fast_reg.page_shift = SHIFT_4K;
-       wr->wr.fast_reg.length = size;
-       wr->wr.fast_reg.rkey = mr->rkey;
-       wr->wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE  |
-                                       IB_ACCESS_REMOTE_WRITE |
-                                       IB_ACCESS_REMOTE_READ);
+       wr = reg_wr(iser_tx_next_wr(tx_desc));
+       wr->wr.opcode = IB_WR_REG_MR;
+       wr->wr.wr_id = ISER_FASTREG_LI_WRID;
+       wr->wr.send_flags = 0;
+       wr->wr.num_sge = 0;
+       wr->mr = mr;
+       wr->key = mr->rkey;
+       wr->access = IB_ACCESS_LOCAL_WRITE  |
+                    IB_ACCESS_REMOTE_WRITE |
+                    IB_ACCESS_REMOTE_READ;
+
        rsc->mr_valid = 0;
 
        reg->sge.lkey = mr->lkey;
        reg->rkey = mr->rkey;
-       reg->sge.addr = frpl->page_list[0] + offset;
-       reg->sge.length = size;
+       reg->sge.addr = mr->iova;
+       reg->sge.length = mr->length;
 
-       iser_dbg("fast reg: lkey=0x%x, rkey=0x%x, addr=0x%llx,"
-                " length=0x%x\n", reg->sge.lkey, reg->rkey,
-                reg->sge.addr, reg->sge.length);
-
-       return 0;
-}
-
-static int
-iser_handle_unaligned_buf(struct iscsi_iser_task *task,
-                         struct iser_data_buf *mem,
-                         enum iser_data_dir dir)
-{
-       struct iser_conn *iser_conn = task->iser_conn;
-       struct iser_device *device = iser_conn->ib_conn.device;
-       int err, aligned_len;
-
-       aligned_len = iser_data_buf_aligned_len(mem, device->ib_device,
-                                               iser_conn->scsi_sg_tablesize);
-       if (aligned_len != mem->dma_nents) {
-               err = fall_to_bounce_buf(task, mem, dir);
-               if (err)
-                       return err;
-       }
+       iser_dbg("lkey=0x%x rkey=0x%x addr=0x%llx length=0x%x\n",
+                reg->sge.lkey, reg->rkey, reg->sge.addr, reg->sge.length);
 
        return 0;
 }
@@ -841,10 +565,6 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task,
        bool use_dma_key;
        int err;
 
-       err = iser_handle_unaligned_buf(task, mem, dir);
-       if (unlikely(err))
-               return err;
-
        use_dma_key = (mem->dma_nents == 1 && !iser_always_reg &&
                       scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL);
 
@@ -867,10 +587,6 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task,
 
                if (scsi_prot_sg_count(task->sc)) {
                        mem = &task->prot[dir];
-                       err = iser_handle_unaligned_buf(task, mem, dir);
-                       if (unlikely(err))
-                               goto err_reg;
-
                        err = iser_reg_prot_sg(task, mem, desc,
                                               use_dma_key, prot_reg);
                        if (unlikely(err))
index 85132d867bc86fcfcd99b7065e9f746301422de1..a93070210109699909075e02212fc6ae70710960 100644 (file)
@@ -293,35 +293,21 @@ iser_alloc_reg_res(struct ib_device *ib_device,
 {
        int ret;
 
-       res->frpl = ib_alloc_fast_reg_page_list(ib_device, size);
-       if (IS_ERR(res->frpl)) {
-               ret = PTR_ERR(res->frpl);
-               iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n",
-                        ret);
-               return PTR_ERR(res->frpl);
-       }
-
        res->mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, size);
        if (IS_ERR(res->mr)) {
                ret = PTR_ERR(res->mr);
                iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret);
-               goto fast_reg_mr_failure;
+               return ret;
        }
        res->mr_valid = 1;
 
        return 0;
-
-fast_reg_mr_failure:
-       ib_free_fast_reg_page_list(res->frpl);
-
-       return ret;
 }
 
 static void
 iser_free_reg_res(struct iser_reg_resources *rsc)
 {
        ib_dereg_mr(rsc->mr);
-       ib_free_fast_reg_page_list(rsc->frpl);
 }
 
 static int
@@ -1017,7 +1003,7 @@ int iser_connect(struct iser_conn   *iser_conn,
        ib_conn->beacon.wr_id = ISER_BEACON_WRID;
        ib_conn->beacon.opcode = IB_WR_SEND;
 
-       ib_conn->cma_id = rdma_create_id(iser_cma_handler,
+       ib_conn->cma_id = rdma_create_id(&init_net, iser_cma_handler,
                                         (void *)iser_conn,
                                         RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ib_conn->cma_id)) {
@@ -1135,7 +1121,7 @@ int iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc,
        wr->opcode = IB_WR_SEND;
        wr->send_flags = signal ? IB_SEND_SIGNALED : 0;
 
-       ib_ret = ib_post_send(ib_conn->qp, &tx_desc->wrs[0], &bad_wr);
+       ib_ret = ib_post_send(ib_conn->qp, &tx_desc->wrs[0].send, &bad_wr);
        if (ib_ret)
                iser_err("ib_post_send failed, ret:%d opcode:%d\n",
                         ib_ret, bad_wr->opcode);
index aa59037d75040b7d6e1126bb620339c1c603bc89..dfbbbb28090b2301c7742fd28b145b62054a76af 100644 (file)
@@ -473,10 +473,8 @@ isert_conn_free_fastreg_pool(struct isert_conn *isert_conn)
        list_for_each_entry_safe(fr_desc, tmp,
                                 &isert_conn->fr_pool, list) {
                list_del(&fr_desc->list);
-               ib_free_fast_reg_page_list(fr_desc->data_frpl);
                ib_dereg_mr(fr_desc->data_mr);
                if (fr_desc->pi_ctx) {
-                       ib_free_fast_reg_page_list(fr_desc->pi_ctx->prot_frpl);
                        ib_dereg_mr(fr_desc->pi_ctx->prot_mr);
                        ib_dereg_mr(fr_desc->pi_ctx->sig_mr);
                        kfree(fr_desc->pi_ctx);
@@ -504,22 +502,13 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc,
                return -ENOMEM;
        }
 
-       pi_ctx->prot_frpl = ib_alloc_fast_reg_page_list(device,
-                                           ISCSI_ISER_SG_TABLESIZE);
-       if (IS_ERR(pi_ctx->prot_frpl)) {
-               isert_err("Failed to allocate prot frpl err=%ld\n",
-                         PTR_ERR(pi_ctx->prot_frpl));
-               ret = PTR_ERR(pi_ctx->prot_frpl);
-               goto err_pi_ctx;
-       }
-
        pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG,
                                      ISCSI_ISER_SG_TABLESIZE);
        if (IS_ERR(pi_ctx->prot_mr)) {
                isert_err("Failed to allocate prot frmr err=%ld\n",
                          PTR_ERR(pi_ctx->prot_mr));
                ret = PTR_ERR(pi_ctx->prot_mr);
-               goto err_prot_frpl;
+               goto err_pi_ctx;
        }
        desc->ind |= ISERT_PROT_KEY_VALID;
 
@@ -539,8 +528,6 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc,
 
 err_prot_mr:
        ib_dereg_mr(pi_ctx->prot_mr);
-err_prot_frpl:
-       ib_free_fast_reg_page_list(pi_ctx->prot_frpl);
 err_pi_ctx:
        kfree(pi_ctx);
 
@@ -551,34 +538,18 @@ static int
 isert_create_fr_desc(struct ib_device *ib_device, struct ib_pd *pd,
                     struct fast_reg_descriptor *fr_desc)
 {
-       int ret;
-
-       fr_desc->data_frpl = ib_alloc_fast_reg_page_list(ib_device,
-                                                        ISCSI_ISER_SG_TABLESIZE);
-       if (IS_ERR(fr_desc->data_frpl)) {
-               isert_err("Failed to allocate data frpl err=%ld\n",
-                         PTR_ERR(fr_desc->data_frpl));
-               return PTR_ERR(fr_desc->data_frpl);
-       }
-
        fr_desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG,
                                       ISCSI_ISER_SG_TABLESIZE);
        if (IS_ERR(fr_desc->data_mr)) {
                isert_err("Failed to allocate data frmr err=%ld\n",
                          PTR_ERR(fr_desc->data_mr));
-               ret = PTR_ERR(fr_desc->data_mr);
-               goto err_data_frpl;
+               return PTR_ERR(fr_desc->data_mr);
        }
        fr_desc->ind |= ISERT_DATA_KEY_VALID;
 
        isert_dbg("Created fr_desc %p\n", fr_desc);
 
        return 0;
-
-err_data_frpl:
-       ib_free_fast_reg_page_list(fr_desc->data_frpl);
-
-       return ret;
 }
 
 static int
@@ -1579,7 +1550,6 @@ isert_rx_do_work(struct iser_rx_desc *rx_desc, struct isert_conn *isert_conn)
        struct iser_hdr *iser_hdr = &rx_desc->iser_header;
        uint64_t read_va = 0, write_va = 0;
        uint32_t read_stag = 0, write_stag = 0;
-       int rc;
 
        switch (iser_hdr->flags & 0xF0) {
        case ISCSI_CTRL:
@@ -1606,8 +1576,8 @@ isert_rx_do_work(struct iser_rx_desc *rx_desc, struct isert_conn *isert_conn)
                break;
        }
 
-       rc = isert_rx_opcode(isert_conn, rx_desc,
-                            read_stag, read_va, write_stag, write_va);
+       isert_rx_opcode(isert_conn, rx_desc,
+                       read_stag, read_va, write_stag, write_va);
 }
 
 static void
@@ -1716,10 +1686,10 @@ isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
                isert_unmap_data_buf(isert_conn, &wr->data);
        }
 
-       if (wr->send_wr) {
+       if (wr->rdma_wr) {
                isert_dbg("Cmd %p free send_wr\n", isert_cmd);
-               kfree(wr->send_wr);
-               wr->send_wr = NULL;
+               kfree(wr->rdma_wr);
+               wr->rdma_wr = NULL;
        }
 
        if (wr->ib_sge) {
@@ -1754,7 +1724,7 @@ isert_unreg_rdma(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
        }
 
        wr->ib_sge = NULL;
-       wr->send_wr = NULL;
+       wr->rdma_wr = NULL;
 }
 
 static void
@@ -1923,7 +1893,7 @@ isert_completion_rdma_write(struct iser_tx_desc *tx_desc,
        }
 
        device->unreg_rdma_mem(isert_cmd, isert_conn);
-       wr->send_wr_num = 0;
+       wr->rdma_wr_num = 0;
        if (ret)
                transport_send_check_condition_and_sense(se_cmd,
                                                         se_cmd->pi_err, 0);
@@ -1951,7 +1921,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
        iscsit_stop_dataout_timer(cmd);
        device->unreg_rdma_mem(isert_cmd, isert_conn);
        cmd->write_data_done = wr->data.len;
-       wr->send_wr_num = 0;
+       wr->rdma_wr_num = 0;
 
        isert_dbg("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
        spin_lock_bh(&cmd->istate_lock);
@@ -2403,7 +2373,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 
 static int
 isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
-                   struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
+                   struct ib_sge *ib_sge, struct ib_rdma_wr *rdma_wr,
                    u32 data_left, u32 offset)
 {
        struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
@@ -2418,8 +2388,8 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
        sg_nents = min(cmd->se_cmd.t_data_nents - sg_off, isert_conn->max_sge);
        page_off = offset % PAGE_SIZE;
 
-       send_wr->sg_list = ib_sge;
-       send_wr->wr_id = (uintptr_t)&isert_cmd->tx_desc;
+       rdma_wr->wr.sg_list = ib_sge;
+       rdma_wr->wr.wr_id = (uintptr_t)&isert_cmd->tx_desc;
        /*
         * Perform mapping of TCM scatterlist memory ib_sge dma_addr.
         */
@@ -2444,11 +2414,11 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
                isert_dbg("Incrementing ib_sge pointer to %p\n", ib_sge);
        }
 
-       send_wr->num_sge = ++i;
+       rdma_wr->wr.num_sge = ++i;
        isert_dbg("Set outgoing sg_list: %p num_sg: %u from TCM SGLs\n",
-                 send_wr->sg_list, send_wr->num_sge);
+                 rdma_wr->wr.sg_list, rdma_wr->wr.num_sge);
 
-       return send_wr->num_sge;
+       return rdma_wr->wr.num_sge;
 }
 
 static int
@@ -2459,7 +2429,7 @@ isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = conn->context;
        struct isert_data_buf *data = &wr->data;
-       struct ib_send_wr *send_wr;
+       struct ib_rdma_wr *rdma_wr;
        struct ib_sge *ib_sge;
        u32 offset, data_len, data_left, rdma_write_max, va_offset = 0;
        int ret = 0, i, ib_sge_cnt;
@@ -2484,11 +2454,11 @@ isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        }
        wr->ib_sge = ib_sge;
 
-       wr->send_wr_num = DIV_ROUND_UP(data->nents, isert_conn->max_sge);
-       wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
+       wr->rdma_wr_num = DIV_ROUND_UP(data->nents, isert_conn->max_sge);
+       wr->rdma_wr = kzalloc(sizeof(struct ib_rdma_wr) * wr->rdma_wr_num,
                                GFP_KERNEL);
-       if (!wr->send_wr) {
-               isert_dbg("Unable to allocate wr->send_wr\n");
+       if (!wr->rdma_wr) {
+               isert_dbg("Unable to allocate wr->rdma_wr\n");
                ret = -ENOMEM;
                goto unmap_cmd;
        }
@@ -2496,31 +2466,31 @@ isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        wr->isert_cmd = isert_cmd;
        rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
 
-       for (i = 0; i < wr->send_wr_num; i++) {
-               send_wr = &isert_cmd->rdma_wr.send_wr[i];
+       for (i = 0; i < wr->rdma_wr_num; i++) {
+               rdma_wr = &isert_cmd->rdma_wr.rdma_wr[i];
                data_len = min(data_left, rdma_write_max);
 
-               send_wr->send_flags = 0;
+               rdma_wr->wr.send_flags = 0;
                if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
-                       send_wr->opcode = IB_WR_RDMA_WRITE;
-                       send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset;
-                       send_wr->wr.rdma.rkey = isert_cmd->read_stag;
-                       if (i + 1 == wr->send_wr_num)
-                               send_wr->next = &isert_cmd->tx_desc.send_wr;
+                       rdma_wr->wr.opcode = IB_WR_RDMA_WRITE;
+                       rdma_wr->remote_addr = isert_cmd->read_va + offset;
+                       rdma_wr->rkey = isert_cmd->read_stag;
+                       if (i + 1 == wr->rdma_wr_num)
+                               rdma_wr->wr.next = &isert_cmd->tx_desc.send_wr;
                        else
-                               send_wr->next = &wr->send_wr[i + 1];
+                               rdma_wr->wr.next = &wr->rdma_wr[i + 1].wr;
                } else {
-                       send_wr->opcode = IB_WR_RDMA_READ;
-                       send_wr->wr.rdma.remote_addr = isert_cmd->write_va + va_offset;
-                       send_wr->wr.rdma.rkey = isert_cmd->write_stag;
-                       if (i + 1 == wr->send_wr_num)
-                               send_wr->send_flags = IB_SEND_SIGNALED;
+                       rdma_wr->wr.opcode = IB_WR_RDMA_READ;
+                       rdma_wr->remote_addr = isert_cmd->write_va + va_offset;
+                       rdma_wr->rkey = isert_cmd->write_stag;
+                       if (i + 1 == wr->rdma_wr_num)
+                               rdma_wr->wr.send_flags = IB_SEND_SIGNALED;
                        else
-                               send_wr->next = &wr->send_wr[i + 1];
+                               rdma_wr->wr.next = &wr->rdma_wr[i + 1].wr;
                }
 
                ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
-                                       send_wr, data_len, offset);
+                                       rdma_wr, data_len, offset);
                ib_sge += ib_sge_cnt;
 
                offset += data_len;
@@ -2535,45 +2505,6 @@ unmap_cmd:
        return ret;
 }
 
-static int
-isert_map_fr_pagelist(struct ib_device *ib_dev,
-                     struct scatterlist *sg_start, int sg_nents, u64 *fr_pl)
-{
-       u64 start_addr, end_addr, page, chunk_start = 0;
-       struct scatterlist *tmp_sg;
-       int i = 0, new_chunk, last_ent, n_pages;
-
-       n_pages = 0;
-       new_chunk = 1;
-       last_ent = sg_nents - 1;
-       for_each_sg(sg_start, tmp_sg, sg_nents, i) {
-               start_addr = ib_sg_dma_address(ib_dev, tmp_sg);
-               if (new_chunk)
-                       chunk_start = start_addr;
-               end_addr = start_addr + ib_sg_dma_len(ib_dev, tmp_sg);
-
-               isert_dbg("SGL[%d] dma_addr: 0x%llx len: %u\n",
-                         i, (unsigned long long)tmp_sg->dma_address,
-                         tmp_sg->length);
-
-               if ((end_addr & ~PAGE_MASK) && i < last_ent) {
-                       new_chunk = 0;
-                       continue;
-               }
-               new_chunk = 1;
-
-               page = chunk_start & PAGE_MASK;
-               do {
-                       fr_pl[n_pages++] = page;
-                       isert_dbg("Mapped page_list[%d] page_addr: 0x%llx\n",
-                                 n_pages - 1, page);
-                       page += PAGE_SIZE;
-               } while (page < end_addr);
-       }
-
-       return n_pages;
-}
-
 static inline void
 isert_inv_rkey(struct ib_send_wr *inv_wr, struct ib_mr *mr)
 {
@@ -2599,11 +2530,9 @@ isert_fast_reg_mr(struct isert_conn *isert_conn,
        struct isert_device *device = isert_conn->device;
        struct ib_device *ib_dev = device->ib_device;
        struct ib_mr *mr;
-       struct ib_fast_reg_page_list *frpl;
-       struct ib_send_wr fr_wr, inv_wr;
-       struct ib_send_wr *bad_wr, *wr = NULL;
-       int ret, pagelist_len;
-       u32 page_off;
+       struct ib_reg_wr reg_wr;
+       struct ib_send_wr inv_wr, *bad_wr, *wr = NULL;
+       int ret, n;
 
        if (mem->dma_nents == 1) {
                sge->lkey = device->pd->local_dma_lkey;
@@ -2614,45 +2543,41 @@ isert_fast_reg_mr(struct isert_conn *isert_conn,
                return 0;
        }
 
-       if (ind == ISERT_DATA_KEY_VALID) {
+       if (ind == ISERT_DATA_KEY_VALID)
                /* Registering data buffer */
                mr = fr_desc->data_mr;
-               frpl = fr_desc->data_frpl;
-       } else {
+       else
                /* Registering protection buffer */
                mr = fr_desc->pi_ctx->prot_mr;
-               frpl = fr_desc->pi_ctx->prot_frpl;
-       }
-
-       page_off = mem->offset % PAGE_SIZE;
-
-       isert_dbg("Use fr_desc %p sg_nents %d offset %u\n",
-                 fr_desc, mem->nents, mem->offset);
-
-       pagelist_len = isert_map_fr_pagelist(ib_dev, mem->sg, mem->nents,
-                                            &frpl->page_list[0]);
 
        if (!(fr_desc->ind & ind)) {
                isert_inv_rkey(&inv_wr, mr);
                wr = &inv_wr;
        }
 
-       /* Prepare FASTREG WR */
-       memset(&fr_wr, 0, sizeof(fr_wr));
-       fr_wr.wr_id = ISER_FASTREG_LI_WRID;
-       fr_wr.opcode = IB_WR_FAST_REG_MR;
-       fr_wr.wr.fast_reg.iova_start = frpl->page_list[0] + page_off;
-       fr_wr.wr.fast_reg.page_list = frpl;
-       fr_wr.wr.fast_reg.page_list_len = pagelist_len;
-       fr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       fr_wr.wr.fast_reg.length = mem->len;
-       fr_wr.wr.fast_reg.rkey = mr->rkey;
-       fr_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE;
+       n = ib_map_mr_sg(mr, mem->sg, mem->nents, PAGE_SIZE);
+       if (unlikely(n != mem->nents)) {
+               isert_err("failed to map mr sg (%d/%d)\n",
+                        n, mem->nents);
+               return n < 0 ? n : -EINVAL;
+       }
+
+       isert_dbg("Use fr_desc %p sg_nents %d offset %u\n",
+                 fr_desc, mem->nents, mem->offset);
+
+       reg_wr.wr.next = NULL;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = ISER_FASTREG_LI_WRID;
+       reg_wr.wr.send_flags = 0;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = mr;
+       reg_wr.key = mr->lkey;
+       reg_wr.access = IB_ACCESS_LOCAL_WRITE;
 
        if (!wr)
-               wr = &fr_wr;
+               wr = &reg_wr.wr;
        else
-               wr->next = &fr_wr;
+               wr->next = &reg_wr.wr;
 
        ret = ib_post_send(isert_conn->qp, wr, &bad_wr);
        if (ret) {
@@ -2662,8 +2587,8 @@ isert_fast_reg_mr(struct isert_conn *isert_conn,
        fr_desc->ind &= ~ind;
 
        sge->lkey = mr->lkey;
-       sge->addr = frpl->page_list[0] + page_off;
-       sge->length = mem->len;
+       sge->addr = mr->iova;
+       sge->length = mr->length;
 
        isert_dbg("sge: addr: 0x%llx  length: %u lkey: %x\n",
                  sge->addr, sge->length, sge->lkey);
@@ -2733,8 +2658,8 @@ isert_reg_sig_mr(struct isert_conn *isert_conn,
                 struct isert_rdma_wr *rdma_wr,
                 struct fast_reg_descriptor *fr_desc)
 {
-       struct ib_send_wr sig_wr, inv_wr;
-       struct ib_send_wr *bad_wr, *wr = NULL;
+       struct ib_sig_handover_wr sig_wr;
+       struct ib_send_wr inv_wr, *bad_wr, *wr = NULL;
        struct pi_context *pi_ctx = fr_desc->pi_ctx;
        struct ib_sig_attrs sig_attrs;
        int ret;
@@ -2752,20 +2677,20 @@ isert_reg_sig_mr(struct isert_conn *isert_conn,
        }
 
        memset(&sig_wr, 0, sizeof(sig_wr));
-       sig_wr.opcode = IB_WR_REG_SIG_MR;
-       sig_wr.wr_id = ISER_FASTREG_LI_WRID;
-       sig_wr.sg_list = &rdma_wr->ib_sg[DATA];
-       sig_wr.num_sge = 1;
-       sig_wr.wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE;
-       sig_wr.wr.sig_handover.sig_attrs = &sig_attrs;
-       sig_wr.wr.sig_handover.sig_mr = pi_ctx->sig_mr;
+       sig_wr.wr.opcode = IB_WR_REG_SIG_MR;
+       sig_wr.wr.wr_id = ISER_FASTREG_LI_WRID;
+       sig_wr.wr.sg_list = &rdma_wr->ib_sg[DATA];
+       sig_wr.wr.num_sge = 1;
+       sig_wr.access_flags = IB_ACCESS_LOCAL_WRITE;
+       sig_wr.sig_attrs = &sig_attrs;
+       sig_wr.sig_mr = pi_ctx->sig_mr;
        if (se_cmd->t_prot_sg)
-               sig_wr.wr.sig_handover.prot = &rdma_wr->ib_sg[PROT];
+               sig_wr.prot = &rdma_wr->ib_sg[PROT];
 
        if (!wr)
-               wr = &sig_wr;
+               wr = &sig_wr.wr;
        else
-               wr->next = &sig_wr;
+               wr->next = &sig_wr.wr;
 
        ret = ib_post_send(isert_conn->qp, wr, &bad_wr);
        if (ret) {
@@ -2859,7 +2784,7 @@ isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = conn->context;
        struct fast_reg_descriptor *fr_desc = NULL;
-       struct ib_send_wr *send_wr;
+       struct ib_rdma_wr *rdma_wr;
        struct ib_sge *ib_sg;
        u32 offset;
        int ret = 0;
@@ -2900,26 +2825,26 @@ isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 
        memcpy(&wr->s_ib_sge, ib_sg, sizeof(*ib_sg));
        wr->ib_sge = &wr->s_ib_sge;
-       wr->send_wr_num = 1;
-       memset(&wr->s_send_wr, 0, sizeof(*send_wr));
-       wr->send_wr = &wr->s_send_wr;
+       wr->rdma_wr_num = 1;
+       memset(&wr->s_rdma_wr, 0, sizeof(wr->s_rdma_wr));
+       wr->rdma_wr = &wr->s_rdma_wr;
        wr->isert_cmd = isert_cmd;
 
-       send_wr = &isert_cmd->rdma_wr.s_send_wr;
-       send_wr->sg_list = &wr->s_ib_sge;
-       send_wr->num_sge = 1;
-       send_wr->wr_id = (uintptr_t)&isert_cmd->tx_desc;
+       rdma_wr = &isert_cmd->rdma_wr.s_rdma_wr;
+       rdma_wr->wr.sg_list = &wr->s_ib_sge;
+       rdma_wr->wr.num_sge = 1;
+       rdma_wr->wr.wr_id = (uintptr_t)&isert_cmd->tx_desc;
        if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
-               send_wr->opcode = IB_WR_RDMA_WRITE;
-               send_wr->wr.rdma.remote_addr = isert_cmd->read_va;
-               send_wr->wr.rdma.rkey = isert_cmd->read_stag;
-               send_wr->send_flags = !isert_prot_cmd(isert_conn, se_cmd) ?
+               rdma_wr->wr.opcode = IB_WR_RDMA_WRITE;
+               rdma_wr->remote_addr = isert_cmd->read_va;
+               rdma_wr->rkey = isert_cmd->read_stag;
+               rdma_wr->wr.send_flags = !isert_prot_cmd(isert_conn, se_cmd) ?
                                      0 : IB_SEND_SIGNALED;
        } else {
-               send_wr->opcode = IB_WR_RDMA_READ;
-               send_wr->wr.rdma.remote_addr = isert_cmd->write_va;
-               send_wr->wr.rdma.rkey = isert_cmd->write_stag;
-               send_wr->send_flags = IB_SEND_SIGNALED;
+               rdma_wr->wr.opcode = IB_WR_RDMA_READ;
+               rdma_wr->remote_addr = isert_cmd->write_va;
+               rdma_wr->rkey = isert_cmd->write_stag;
+               rdma_wr->wr.send_flags = IB_SEND_SIGNALED;
        }
 
        return 0;
@@ -2967,8 +2892,8 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
                isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
                isert_init_send_wr(isert_conn, isert_cmd,
                                   &isert_cmd->tx_desc.send_wr);
-               isert_cmd->rdma_wr.s_send_wr.next = &isert_cmd->tx_desc.send_wr;
-               wr->send_wr_num += 1;
+               isert_cmd->rdma_wr.s_rdma_wr.wr.next = &isert_cmd->tx_desc.send_wr;
+               wr->rdma_wr_num += 1;
 
                rc = isert_post_recv(isert_conn, isert_cmd->rx_desc);
                if (rc) {
@@ -2977,7 +2902,7 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
                }
        }
 
-       rc = ib_post_send(isert_conn->qp, wr->send_wr, &wr_failed);
+       rc = ib_post_send(isert_conn->qp, &wr->rdma_wr->wr, &wr_failed);
        if (rc)
                isert_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
 
@@ -3011,7 +2936,7 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
                return rc;
        }
 
-       rc = ib_post_send(isert_conn->qp, wr->send_wr, &wr_failed);
+       rc = ib_post_send(isert_conn->qp, &wr->rdma_wr->wr, &wr_failed);
        if (rc)
                isert_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
 
@@ -3097,7 +3022,7 @@ isert_setup_id(struct isert_np *isert_np)
        sa = (struct sockaddr *)&np->np_sockaddr;
        isert_dbg("ksockaddr: %p, sa: %p\n", &np->np_sockaddr, sa);
 
-       id = rdma_create_id(isert_cma_handler, isert_np,
+       id = rdma_create_id(&init_net, isert_cma_handler, isert_np,
                            RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(id)) {
                isert_err("rdma_create_id() failed: %ld\n", PTR_ERR(id));
index c5b99bcecbcff806945be8baa9cc6dbeca46418a..3d7fbc47c3434c32308136b7faec65590b74d439 100644 (file)
@@ -84,14 +84,12 @@ enum isert_indicator {
 
 struct pi_context {
        struct ib_mr                   *prot_mr;
-       struct ib_fast_reg_page_list   *prot_frpl;
        struct ib_mr                   *sig_mr;
 };
 
 struct fast_reg_descriptor {
        struct list_head                list;
        struct ib_mr                   *data_mr;
-       struct ib_fast_reg_page_list   *data_frpl;
        u8                              ind;
        struct pi_context              *pi_ctx;
 };
@@ -117,9 +115,9 @@ struct isert_rdma_wr {
        enum iser_ib_op_code    iser_ib_op;
        struct ib_sge           *ib_sge;
        struct ib_sge           s_ib_sge;
-       int                     send_wr_num;
-       struct ib_send_wr       *send_wr;
-       struct ib_send_wr       s_send_wr;
+       int                     rdma_wr_num;
+       struct ib_rdma_wr       *rdma_wr;
+       struct ib_rdma_wr       s_rdma_wr;
        struct ib_sge           ib_sg[3];
        struct isert_data_buf   data;
        struct isert_data_buf   prot;
index b481490ad25756f6de36cd718c0983be751c8e5c..32f79624dd28565d3846384f24049e435aef83e7 100644 (file)
@@ -340,8 +340,6 @@ static void srp_destroy_fr_pool(struct srp_fr_pool *pool)
                return;
 
        for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
-               if (d->frpl)
-                       ib_free_fast_reg_page_list(d->frpl);
                if (d->mr)
                        ib_dereg_mr(d->mr);
        }
@@ -362,7 +360,6 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device,
        struct srp_fr_pool *pool;
        struct srp_fr_desc *d;
        struct ib_mr *mr;
-       struct ib_fast_reg_page_list *frpl;
        int i, ret = -EINVAL;
 
        if (pool_size <= 0)
@@ -385,12 +382,6 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device,
                        goto destroy_pool;
                }
                d->mr = mr;
-               frpl = ib_alloc_fast_reg_page_list(device, max_page_list_len);
-               if (IS_ERR(frpl)) {
-                       ret = PTR_ERR(frpl);
-                       goto destroy_pool;
-               }
-               d->frpl = frpl;
                list_add_tail(&d->entry, &pool->free_list);
        }
 
@@ -849,11 +840,12 @@ static void srp_free_req_data(struct srp_target_port *target,
 
        for (i = 0; i < target->req_ring_size; ++i) {
                req = &ch->req_ring[i];
-               if (dev->use_fast_reg)
+               if (dev->use_fast_reg) {
                        kfree(req->fr_list);
-               else
+               } else {
                        kfree(req->fmr_list);
-               kfree(req->map_page);
+                       kfree(req->map_page);
+               }
                if (req->indirect_dma_addr) {
                        ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
                                            target->indirect_size,
@@ -887,14 +879,15 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch)
                                  GFP_KERNEL);
                if (!mr_list)
                        goto out;
-               if (srp_dev->use_fast_reg)
+               if (srp_dev->use_fast_reg) {
                        req->fr_list = mr_list;
-               else
+               } else {
                        req->fmr_list = mr_list;
-               req->map_page = kmalloc(srp_dev->max_pages_per_mr *
-                                       sizeof(void *), GFP_KERNEL);
-               if (!req->map_page)
-                       goto out;
+                       req->map_page = kmalloc(srp_dev->max_pages_per_mr *
+                                               sizeof(void *), GFP_KERNEL);
+                       if (!req->map_page)
+                               goto out;
+               }
                req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
                if (!req->indirect_desc)
                        goto out;
@@ -1286,6 +1279,17 @@ static int srp_map_finish_fmr(struct srp_map_state *state,
        if (state->fmr.next >= state->fmr.end)
                return -ENOMEM;
 
+       WARN_ON_ONCE(!dev->use_fmr);
+
+       if (state->npages == 0)
+               return 0;
+
+       if (state->npages == 1 && target->global_mr) {
+               srp_map_desc(state, state->base_dma_addr, state->dma_len,
+                            target->global_mr->rkey);
+               goto reset_state;
+       }
+
        fmr = ib_fmr_pool_map_phys(ch->fmr_pool, state->pages,
                                   state->npages, io_addr);
        if (IS_ERR(fmr))
@@ -1297,6 +1301,10 @@ static int srp_map_finish_fmr(struct srp_map_state *state,
        srp_map_desc(state, state->base_dma_addr & ~dev->mr_page_mask,
                     state->dma_len, fmr->fmr->rkey);
 
+reset_state:
+       state->npages = 0;
+       state->dma_len = 0;
+
        return 0;
 }
 
@@ -1306,13 +1314,26 @@ static int srp_map_finish_fr(struct srp_map_state *state,
        struct srp_target_port *target = ch->target;
        struct srp_device *dev = target->srp_host->srp_dev;
        struct ib_send_wr *bad_wr;
-       struct ib_send_wr wr;
+       struct ib_reg_wr wr;
        struct srp_fr_desc *desc;
        u32 rkey;
+       int n, err;
 
        if (state->fr.next >= state->fr.end)
                return -ENOMEM;
 
+       WARN_ON_ONCE(!dev->use_fast_reg);
+
+       if (state->sg_nents == 0)
+               return 0;
+
+       if (state->sg_nents == 1 && target->global_mr) {
+               srp_map_desc(state, sg_dma_address(state->sg),
+                            sg_dma_len(state->sg),
+                            target->global_mr->rkey);
+               return 1;
+       }
+
        desc = srp_fr_pool_get(ch->fr_pool);
        if (!desc)
                return -ENOMEM;
@@ -1320,56 +1341,33 @@ static int srp_map_finish_fr(struct srp_map_state *state,
        rkey = ib_inc_rkey(desc->mr->rkey);
        ib_update_fast_reg_key(desc->mr, rkey);
 
-       memcpy(desc->frpl->page_list, state->pages,
-              sizeof(state->pages[0]) * state->npages);
-
-       memset(&wr, 0, sizeof(wr));
-       wr.opcode = IB_WR_FAST_REG_MR;
-       wr.wr_id = FAST_REG_WR_ID_MASK;
-       wr.wr.fast_reg.iova_start = state->base_dma_addr;
-       wr.wr.fast_reg.page_list = desc->frpl;
-       wr.wr.fast_reg.page_list_len = state->npages;
-       wr.wr.fast_reg.page_shift = ilog2(dev->mr_page_size);
-       wr.wr.fast_reg.length = state->dma_len;
-       wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE |
-                                      IB_ACCESS_REMOTE_READ |
-                                      IB_ACCESS_REMOTE_WRITE);
-       wr.wr.fast_reg.rkey = desc->mr->lkey;
+       n = ib_map_mr_sg(desc->mr, state->sg, state->sg_nents,
+                        dev->mr_page_size);
+       if (unlikely(n < 0))
+               return n;
+
+       wr.wr.next = NULL;
+       wr.wr.opcode = IB_WR_REG_MR;
+       wr.wr.wr_id = FAST_REG_WR_ID_MASK;
+       wr.wr.num_sge = 0;
+       wr.wr.send_flags = 0;
+       wr.mr = desc->mr;
+       wr.key = desc->mr->rkey;
+       wr.access = (IB_ACCESS_LOCAL_WRITE |
+                    IB_ACCESS_REMOTE_READ |
+                    IB_ACCESS_REMOTE_WRITE);
 
        *state->fr.next++ = desc;
        state->nmdesc++;
 
-       srp_map_desc(state, state->base_dma_addr, state->dma_len,
-                    desc->mr->rkey);
+       srp_map_desc(state, desc->mr->iova,
+                    desc->mr->length, desc->mr->rkey);
 
-       return ib_post_send(ch->qp, &wr, &bad_wr);
-}
+       err = ib_post_send(ch->qp, &wr.wr, &bad_wr);
+       if (unlikely(err))
+               return err;
 
-static int srp_finish_mapping(struct srp_map_state *state,
-                             struct srp_rdma_ch *ch)
-{
-       struct srp_target_port *target = ch->target;
-       struct srp_device *dev = target->srp_host->srp_dev;
-       int ret = 0;
-
-       WARN_ON_ONCE(!dev->use_fast_reg && !dev->use_fmr);
-
-       if (state->npages == 0)
-               return 0;
-
-       if (state->npages == 1 && target->global_mr)
-               srp_map_desc(state, state->base_dma_addr, state->dma_len,
-                            target->global_mr->rkey);
-       else
-               ret = dev->use_fast_reg ? srp_map_finish_fr(state, ch) :
-                       srp_map_finish_fmr(state, ch);
-
-       if (ret == 0) {
-               state->npages = 0;
-               state->dma_len = 0;
-       }
-
-       return ret;
+       return n;
 }
 
 static int srp_map_sg_entry(struct srp_map_state *state,
@@ -1389,7 +1387,7 @@ static int srp_map_sg_entry(struct srp_map_state *state,
        while (dma_len) {
                unsigned offset = dma_addr & ~dev->mr_page_mask;
                if (state->npages == dev->max_pages_per_mr || offset != 0) {
-                       ret = srp_finish_mapping(state, ch);
+                       ret = srp_map_finish_fmr(state, ch);
                        if (ret)
                                return ret;
                }
@@ -1411,51 +1409,83 @@ static int srp_map_sg_entry(struct srp_map_state *state,
         */
        ret = 0;
        if (len != dev->mr_page_size)
-               ret = srp_finish_mapping(state, ch);
+               ret = srp_map_finish_fmr(state, ch);
        return ret;
 }
 
-static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch,
-                     struct srp_request *req, struct scatterlist *scat,
-                     int count)
+static int srp_map_sg_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch,
+                         struct srp_request *req, struct scatterlist *scat,
+                         int count)
 {
-       struct srp_target_port *target = ch->target;
-       struct srp_device *dev = target->srp_host->srp_dev;
        struct scatterlist *sg;
        int i, ret;
 
-       state->desc     = req->indirect_desc;
-       state->pages    = req->map_page;
-       if (dev->use_fast_reg) {
-               state->fr.next = req->fr_list;
-               state->fr.end = req->fr_list + target->cmd_sg_cnt;
-       } else if (dev->use_fmr) {
-               state->fmr.next = req->fmr_list;
-               state->fmr.end = req->fmr_list + target->cmd_sg_cnt;
-       }
+       state->desc = req->indirect_desc;
+       state->pages = req->map_page;
+       state->fmr.next = req->fmr_list;
+       state->fmr.end = req->fmr_list + ch->target->cmd_sg_cnt;
 
-       if (dev->use_fast_reg || dev->use_fmr) {
-               for_each_sg(scat, sg, count, i) {
-                       ret = srp_map_sg_entry(state, ch, sg, i);
-                       if (ret)
-                               goto out;
-               }
-               ret = srp_finish_mapping(state, ch);
+       for_each_sg(scat, sg, count, i) {
+               ret = srp_map_sg_entry(state, ch, sg, i);
                if (ret)
-                       goto out;
-       } else {
-               for_each_sg(scat, sg, count, i) {
-                       srp_map_desc(state, ib_sg_dma_address(dev->dev, sg),
-                                    ib_sg_dma_len(dev->dev, sg),
-                                    target->global_mr->rkey);
-               }
+                       return ret;
        }
 
+       ret = srp_map_finish_fmr(state, ch);
+       if (ret)
+               return ret;
+
        req->nmdesc = state->nmdesc;
-       ret = 0;
 
-out:
-       return ret;
+       return 0;
+}
+
+static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
+                        struct srp_request *req, struct scatterlist *scat,
+                        int count)
+{
+       state->desc = req->indirect_desc;
+       state->fr.next = req->fr_list;
+       state->fr.end = req->fr_list + ch->target->cmd_sg_cnt;
+       state->sg = scat;
+       state->sg_nents = scsi_sg_count(req->scmnd);
+
+       while (state->sg_nents) {
+               int i, n;
+
+               n = srp_map_finish_fr(state, ch);
+               if (unlikely(n < 0))
+                       return n;
+
+               state->sg_nents -= n;
+               for (i = 0; i < n; i++)
+                       state->sg = sg_next(state->sg);
+       }
+
+       req->nmdesc = state->nmdesc;
+
+       return 0;
+}
+
+static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch,
+                         struct srp_request *req, struct scatterlist *scat,
+                         int count)
+{
+       struct srp_target_port *target = ch->target;
+       struct srp_device *dev = target->srp_host->srp_dev;
+       struct scatterlist *sg;
+       int i;
+
+       state->desc = req->indirect_desc;
+       for_each_sg(scat, sg, count, i) {
+               srp_map_desc(state, ib_sg_dma_address(dev->dev, sg),
+                            ib_sg_dma_len(dev->dev, sg),
+                            target->global_mr->rkey);
+       }
+
+       req->nmdesc = state->nmdesc;
+
+       return 0;
 }
 
 /*
@@ -1474,6 +1504,7 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
        struct srp_map_state state;
        struct srp_direct_buf idb_desc;
        u64 idb_pages[1];
+       struct scatterlist idb_sg[1];
        int ret;
 
        memset(&state, 0, sizeof(state));
@@ -1481,20 +1512,32 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
        state.gen.next = next_mr;
        state.gen.end = end_mr;
        state.desc = &idb_desc;
-       state.pages = idb_pages;
-       state.pages[0] = (req->indirect_dma_addr &
-                         dev->mr_page_mask);
-       state.npages = 1;
        state.base_dma_addr = req->indirect_dma_addr;
        state.dma_len = idb_len;
-       ret = srp_finish_mapping(&state, ch);
-       if (ret < 0)
-               goto out;
+
+       if (dev->use_fast_reg) {
+               state.sg = idb_sg;
+               state.sg_nents = 1;
+               sg_set_buf(idb_sg, req->indirect_desc, idb_len);
+               idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
+               ret = srp_map_finish_fr(&state, ch);
+               if (ret < 0)
+                       return ret;
+       } else if (dev->use_fmr) {
+               state.pages = idb_pages;
+               state.pages[0] = (req->indirect_dma_addr &
+                                 dev->mr_page_mask);
+               state.npages = 1;
+               ret = srp_map_finish_fmr(&state, ch);
+               if (ret < 0)
+                       return ret;
+       } else {
+               return -EINVAL;
+       }
 
        *idb_rkey = idb_desc.key;
 
-out:
-       return ret;
+       return 0;
 }
 
 static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
@@ -1563,7 +1606,12 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                                   target->indirect_size, DMA_TO_DEVICE);
 
        memset(&state, 0, sizeof(state));
-       srp_map_sg(&state, ch, req, scat, count);
+       if (dev->use_fast_reg)
+               srp_map_sg_fr(&state, ch, req, scat, count);
+       else if (dev->use_fmr)
+               srp_map_sg_fmr(&state, ch, req, scat, count);
+       else
+               srp_map_sg_dma(&state, ch, req, scat, count);
 
        /* We've mapped the request, now pull as much of the indirect
         * descriptor table as we can into the command buffer. If this
@@ -3213,7 +3261,7 @@ static ssize_t srp_create_target(struct device *dev,
        INIT_WORK(&target->tl_err_work, srp_tl_err_work);
        INIT_WORK(&target->remove_work, srp_remove_work);
        spin_lock_init(&target->lock);
-       ret = ib_query_gid(ibdev, host->port, 0, &target->sgid);
+       ret = ib_query_gid(ibdev, host->port, 0, &target->sgid, NULL);
        if (ret)
                goto out;
 
index 3608f2e4819c412ee742bca4499cd84de32aa343..87a2a919dc43877141426e6d373d12727dc4b65e 100644 (file)
@@ -242,7 +242,6 @@ struct srp_iu {
 struct srp_fr_desc {
        struct list_head                entry;
        struct ib_mr                    *mr;
-       struct ib_fast_reg_page_list    *frpl;
 };
 
 /**
@@ -294,11 +293,17 @@ struct srp_map_state {
                } gen;
        };
        struct srp_direct_buf  *desc;
-       u64                    *pages;
+       union {
+               u64                     *pages;
+               struct scatterlist      *sg;
+       };
        dma_addr_t              base_dma_addr;
        u32                     dma_len;
        u32                     total_len;
-       unsigned int            npages;
+       union {
+               unsigned int    npages;
+               int             sg_nents;
+       };
        unsigned int            nmdesc;
        unsigned int            ndesc;
 };
index f6fe0414139beeafa3ddfba0ed33bf1ebc6a7489..47c4022fda7680e3107710bb703e83fa61affc15 100644 (file)
@@ -546,7 +546,8 @@ static int srpt_refresh_port(struct srpt_port *sport)
        sport->sm_lid = port_attr.sm_lid;
        sport->lid = port_attr.lid;
 
-       ret = ib_query_gid(sport->sdev->device, sport->port, 0, &sport->gid);
+       ret = ib_query_gid(sport->sdev->device, sport->port, 0, &sport->gid,
+                          NULL);
        if (ret)
                goto err_query_port;
 
@@ -2822,7 +2823,7 @@ static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
                              struct srpt_send_ioctx *ioctx)
 {
-       struct ib_send_wr wr;
+       struct ib_rdma_wr wr;
        struct ib_send_wr *bad_wr;
        struct rdma_iu *riu;
        int i;
@@ -2850,29 +2851,29 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
 
        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 ?
+                       wr.wr.opcode = IB_WR_RDMA_WRITE;
+                       wr.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 ?
+                       wr.wr.opcode = IB_WR_RDMA_READ;
+                       wr.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;
+               wr.wr.next = NULL;
+               wr.remote_addr = riu->raddr;
+               wr.rkey = riu->rkey;
+               wr.wr.num_sge = riu->sge_cnt;
+               wr.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;
+                       wr.wr.send_flags = IB_SEND_SIGNALED;
 
-               ret = ib_post_send(ch->qp, &wr, &bad_wr);
+               ret = ib_post_send(ch->qp, &wr.wr, &bad_wr);
                if (ret)
                        break;
        }
@@ -2881,11 +2882,11 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
                pr_err("%s[%d]: ib_post_send() returned %d for %d/%d\n",
                                 __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;
+               wr.wr.num_sge = 0;
+               wr.wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index);
+               wr.wr.send_flags = IB_SEND_SIGNALED;
                while (ch->state == CH_LIVE &&
-                       ib_post_send(ch->qp, &wr, &bad_wr) != 0) {
+                       ib_post_send(ch->qp, &wr.wr, &bad_wr) != 0) {
                        pr_info("Trying to abort failed RDMA transfer [%d]\n",
                                ioctx->ioctx.index);
                        msleep(1000);
index 08d496411f7570bf73368cdfc32b01ed98c59da8..e9ae3d500a55e368ed4f1a0b1702e7fbdec0935a 100644 (file)
@@ -56,12 +56,57 @@ struct evdev_client {
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
-       int clk_type;
+       unsigned int clk_type;
        bool revoked;
+       unsigned long *evmasks[EV_CNT];
        unsigned int bufsize;
        struct input_event buffer[];
 };
 
+static size_t evdev_get_mask_cnt(unsigned int type)
+{
+       static const size_t counts[EV_CNT] = {
+               /* EV_SYN==0 is EV_CNT, _not_ SYN_CNT, see EVIOCGBIT */
+               [EV_SYN]        = EV_CNT,
+               [EV_KEY]        = KEY_CNT,
+               [EV_REL]        = REL_CNT,
+               [EV_ABS]        = ABS_CNT,
+               [EV_MSC]        = MSC_CNT,
+               [EV_SW]         = SW_CNT,
+               [EV_LED]        = LED_CNT,
+               [EV_SND]        = SND_CNT,
+               [EV_FF]         = FF_CNT,
+       };
+
+       return (type < EV_CNT) ? counts[type] : 0;
+}
+
+/* requires the buffer lock to be held */
+static bool __evdev_is_filtered(struct evdev_client *client,
+                               unsigned int type,
+                               unsigned int code)
+{
+       unsigned long *mask;
+       size_t cnt;
+
+       /* EV_SYN and unknown codes are never filtered */
+       if (type == EV_SYN || type >= EV_CNT)
+               return false;
+
+       /* first test whether the type is filtered */
+       mask = client->evmasks[0];
+       if (mask && !test_bit(type, mask))
+               return true;
+
+       /* unknown values are never filtered */
+       cnt = evdev_get_mask_cnt(type);
+       if (!cnt || code >= cnt)
+               return false;
+
+       mask = client->evmasks[type];
+       return mask && !test_bit(code, mask);
+}
+
 /* flush queued events of type @type, caller must hold client->buffer_lock */
 static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
 {
@@ -146,37 +191,39 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
 static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
 {
        unsigned long flags;
-
-       if (client->clk_type == clkid)
-               return 0;
+       unsigned int clk_type;
 
        switch (clkid) {
 
        case CLOCK_REALTIME:
-               client->clk_type = EV_CLK_REAL;
+               clk_type = EV_CLK_REAL;
                break;
        case CLOCK_MONOTONIC:
-               client->clk_type = EV_CLK_MONO;
+               clk_type = EV_CLK_MONO;
                break;
        case CLOCK_BOOTTIME:
-               client->clk_type = EV_CLK_BOOT;
+               clk_type = EV_CLK_BOOT;
                break;
        default:
                return -EINVAL;
        }
 
-       /*
-        * Flush pending events and queue SYN_DROPPED event,
-        * but only if the queue is not empty.
-        */
-       spin_lock_irqsave(&client->buffer_lock, flags);
+       if (client->clk_type != clk_type) {
+               client->clk_type = clk_type;
 
-       if (client->head != client->tail) {
-               client->packet_head = client->head = client->tail;
-               __evdev_queue_syn_dropped(client);
-       }
+               /*
+                * Flush pending events and queue SYN_DROPPED event,
+                * but only if the queue is not empty.
+                */
+               spin_lock_irqsave(&client->buffer_lock, flags);
 
-       spin_unlock_irqrestore(&client->buffer_lock, flags);
+               if (client->head != client->tail) {
+                       client->packet_head = client->head = client->tail;
+                       __evdev_queue_syn_dropped(client);
+               }
+
+               spin_unlock_irqrestore(&client->buffer_lock, flags);
+       }
 
        return 0;
 }
@@ -226,12 +273,21 @@ static void evdev_pass_values(struct evdev_client *client,
        spin_lock(&client->buffer_lock);
 
        for (v = vals; v != vals + count; v++) {
+               if (__evdev_is_filtered(client, v->type, v->code))
+                       continue;
+
+               if (v->type == EV_SYN && v->code == SYN_REPORT) {
+                       /* drop empty SYN_REPORT */
+                       if (client->packet_head == client->head)
+                               continue;
+
+                       wakeup = true;
+               }
+
                event.type = v->type;
                event.code = v->code;
                event.value = v->value;
                __pass_event(client, &event);
-               if (v->type == EV_SYN && v->code == SYN_REPORT)
-                       wakeup = true;
        }
 
        spin_unlock(&client->buffer_lock);
@@ -410,6 +466,7 @@ static int evdev_release(struct inode *inode, struct file *file)
 {
        struct evdev_client *client = file->private_data;
        struct evdev *evdev = client->evdev;
+       unsigned int i;
 
        mutex_lock(&evdev->mutex);
        evdev_ungrab(evdev, client);
@@ -417,6 +474,9 @@ static int evdev_release(struct inode *inode, struct file *file)
 
        evdev_detach_client(evdev, client);
 
+       for (i = 0; i < EV_CNT; ++i)
+               kfree(client->evmasks[i]);
+
        kvfree(client);
 
        evdev_close_device(evdev);
@@ -627,7 +687,46 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 
        return len;
 }
+
+static int bits_from_user(unsigned long *bits, unsigned int maxbit,
+                         unsigned int maxlen, const void __user *p, int compat)
+{
+       int len, i;
+
+       if (compat) {
+               if (maxlen % sizeof(compat_long_t))
+                       return -EINVAL;
+
+               len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
+               if (len > maxlen)
+                       len = maxlen;
+
+               for (i = 0; i < len / sizeof(compat_long_t); i++)
+                       if (copy_from_user((compat_long_t *) bits +
+                                               i + 1 - ((i % 2) << 1),
+                                          (compat_long_t __user *) p + i,
+                                          sizeof(compat_long_t)))
+                               return -EFAULT;
+               if (i % 2)
+                       *((compat_long_t *) bits + i - 1) = 0;
+
+       } else {
+               if (maxlen % sizeof(long))
+                       return -EINVAL;
+
+               len = BITS_TO_LONGS(maxbit) * sizeof(long);
+               if (len > maxlen)
+                       len = maxlen;
+
+               if (copy_from_user(bits, p, len))
+                       return -EFAULT;
+       }
+
+       return len;
+}
+
 #else
+
 static int bits_to_user(unsigned long *bits, unsigned int maxbit,
                        unsigned int maxlen, void __user *p, int compat)
 {
@@ -640,6 +739,24 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 
        return copy_to_user(p, bits, len) ? -EFAULT : len;
 }
+
+static int bits_from_user(unsigned long *bits, unsigned int maxbit,
+                         unsigned int maxlen, const void __user *p, int compat)
+{
+       size_t chunk_size = compat ? sizeof(compat_long_t) : sizeof(long);
+       int len;
+
+       if (maxlen % chunk_size)
+               return -EINVAL;
+
+       len = compat ? BITS_TO_LONGS_COMPAT(maxbit) : BITS_TO_LONGS(maxbit);
+       len *= chunk_size;
+       if (len > maxlen)
+               len = maxlen;
+
+       return copy_from_user(bits, p, len) ? -EFAULT : len;
+}
+
 #endif /* __BIG_ENDIAN */
 
 #else
@@ -655,6 +772,21 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
        return copy_to_user(p, bits, len) ? -EFAULT : len;
 }
 
+static int bits_from_user(unsigned long *bits, unsigned int maxbit,
+                         unsigned int maxlen, const void __user *p, int compat)
+{
+       int len;
+
+       if (maxlen % sizeof(long))
+               return -EINVAL;
+
+       len = BITS_TO_LONGS(maxbit) * sizeof(long);
+       if (len > maxlen)
+               len = maxlen;
+
+       return copy_from_user(bits, p, len) ? -EFAULT : len;
+}
+
 #endif /* CONFIG_COMPAT */
 
 static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
@@ -849,6 +981,81 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
        return 0;
 }
 
+/* must be called with evdev-mutex held */
+static int evdev_set_mask(struct evdev_client *client,
+                         unsigned int type,
+                         const void __user *codes,
+                         u32 codes_size,
+                         int compat)
+{
+       unsigned long flags, *mask, *oldmask;
+       size_t cnt;
+       int error;
+
+       /* we allow unknown types and 'codes_size > size' for forward-compat */
+       cnt = evdev_get_mask_cnt(type);
+       if (!cnt)
+               return 0;
+
+       mask = kcalloc(sizeof(unsigned long), BITS_TO_LONGS(cnt), GFP_KERNEL);
+       if (!mask)
+               return -ENOMEM;
+
+       error = bits_from_user(mask, cnt - 1, codes_size, codes, compat);
+       if (error < 0) {
+               kfree(mask);
+               return error;
+       }
+
+       spin_lock_irqsave(&client->buffer_lock, flags);
+       oldmask = client->evmasks[type];
+       client->evmasks[type] = mask;
+       spin_unlock_irqrestore(&client->buffer_lock, flags);
+
+       kfree(oldmask);
+
+       return 0;
+}
+
+/* must be called with evdev-mutex held */
+static int evdev_get_mask(struct evdev_client *client,
+                         unsigned int type,
+                         void __user *codes,
+                         u32 codes_size,
+                         int compat)
+{
+       unsigned long *mask;
+       size_t cnt, size, xfer_size;
+       int i;
+       int error;
+
+       /* we allow unknown types and 'codes_size > size' for forward-compat */
+       cnt = evdev_get_mask_cnt(type);
+       size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
+       xfer_size = min_t(size_t, codes_size, size);
+
+       if (cnt > 0) {
+               mask = client->evmasks[type];
+               if (mask) {
+                       error = bits_to_user(mask, cnt - 1,
+                                            xfer_size, codes, compat);
+                       if (error < 0)
+                               return error;
+               } else {
+                       /* fake mask with all bits set */
+                       for (i = 0; i < xfer_size; i++)
+                               if (put_user(0xffU, (u8 __user *)codes + i))
+                                       return -EFAULT;
+               }
+       }
+
+       if (xfer_size < codes_size)
+               if (clear_user(codes + xfer_size, codes_size - xfer_size))
+                       return -EFAULT;
+
+       return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                           void __user *p, int compat_mode)
 {
@@ -856,6 +1063,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
        struct evdev *evdev = client->evdev;
        struct input_dev *dev = evdev->handle.dev;
        struct input_absinfo abs;
+       struct input_mask mask;
        struct ff_effect effect;
        int __user *ip = (int __user *)p;
        unsigned int i, t, u, v;
@@ -917,6 +1125,30 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                else
                        return evdev_revoke(evdev, client, file);
 
+       case EVIOCGMASK: {
+               void __user *codes_ptr;
+
+               if (copy_from_user(&mask, p, sizeof(mask)))
+                       return -EFAULT;
+
+               codes_ptr = (void __user *)(unsigned long)mask.codes_ptr;
+               return evdev_get_mask(client,
+                                     mask.type, codes_ptr, mask.codes_size,
+                                     compat_mode);
+       }
+
+       case EVIOCSMASK: {
+               const void __user *codes_ptr;
+
+               if (copy_from_user(&mask, p, sizeof(mask)))
+                       return -EFAULT;
+
+               codes_ptr = (const void __user *)(unsigned long)mask.codes_ptr;
+               return evdev_set_mask(client,
+                                     mask.type, codes_ptr, mask.codes_size,
+                                     compat_mode);
+       }
+
        case EVIOCSCLOCKID:
                if (copy_from_user(&i, p, sizeof(unsigned int)))
                        return -EFAULT;
index c642082671987f98963ff7b07758a678aaffc480..8f2042432c85151b25fab1e885fe321e1563d641 100644 (file)
@@ -273,14 +273,14 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
 
        switch (code) {
        case FF_GAIN:
-               if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
+               if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffffU)
                        break;
 
                ff->set_gain(dev, value);
                break;
 
        case FF_AUTOCENTER:
-               if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff)
+               if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffffU)
                        break;
 
                ff->set_autocenter(dev, value);
@@ -318,6 +318,11 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects)
                return -EINVAL;
        }
 
+       if (max_effects > FF_MAX_EFFECTS) {
+               dev_err(&dev->dev, "cannot allocate more than FF_MAX_EFFECTS effects\n");
+               return -EINVAL;
+       }
+
        ff_dev_size = sizeof(struct ff_device) +
                                max_effects * sizeof(struct file *);
        if (ff_dev_size < max_effects) /* overflow */
index 5391abd28b2799c6776cf1bc8a398f70ed8382d7..880605959aa6f74a87da70b24f813d2ce428af9f 100644 (file)
@@ -2044,6 +2044,23 @@ static void devm_input_device_unregister(struct device *dev, void *res)
        __input_unregister_device(input);
 }
 
+/**
+ * input_enable_softrepeat - enable software autorepeat
+ * @dev: input device
+ * @delay: repeat delay
+ * @period: repeat period
+ *
+ * Enable software autorepeat on the input device.
+ */
+void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
+{
+       dev->timer.data = (unsigned long) dev;
+       dev->timer.function = input_repeat_key;
+       dev->rep[REP_DELAY] = delay;
+       dev->rep[REP_PERIOD] = period;
+}
+EXPORT_SYMBOL(input_enable_softrepeat);
+
 /**
  * input_register_device - register device with input core
  * @dev: device to be registered
@@ -2108,12 +2125,8 @@ int input_register_device(struct input_dev *dev)
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
         */
-       if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
-               dev->timer.data = (long) dev;
-               dev->timer.function = input_repeat_key;
-               dev->rep[REP_DELAY] = 250;
-               dev->rep[REP_PERIOD] = 33;
-       }
+       if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
+               input_enable_softrepeat(dev, 250, 33);
 
        if (!dev->getkeycode)
                dev->getkeycode = input_default_getkeycode;
index 6cb5a3e5f9a106321aa73de1a4d4265df1022575..5d11fea3c8eccd10dbd892d4898d4b0ecca3aacd 100644 (file)
@@ -444,14 +444,9 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
        len = min(len, sizeof(joydev->abspam));
 
        /* Validate the map. */
-       abspam = kmalloc(len, GFP_KERNEL);
-       if (!abspam)
-               return -ENOMEM;
-
-       if (copy_from_user(abspam, argp, len)) {
-               retval = -EFAULT;
-               goto out;
-       }
+       abspam = memdup_user(argp, len);
+       if (IS_ERR(abspam))
+               return PTR_ERR(abspam);
 
        for (i = 0; i < joydev->nabs; i++) {
                if (abspam[i] > ABS_MAX) {
@@ -480,14 +475,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
        len = min(len, sizeof(joydev->keypam));
 
        /* Validate the map. */
-       keypam = kmalloc(len, GFP_KERNEL);
-       if (!keypam)
-               return -ENOMEM;
-
-       if (copy_from_user(keypam, argp, len)) {
-               retval = -EFAULT;
-               goto out;
-       }
+       keypam = memdup_user(argp, len);
+       if (IS_ERR(keypam))
+               return PTR_ERR(keypam);
 
        for (i = 0; i < joydev->nkey; i++) {
                if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
index 8e7de5c7754ffa98ef0fb869e7668b00b9a32be4..932d07307454bd47441da61ff06e3ef03ea93cd4 100644 (file)
@@ -48,7 +48,7 @@ struct db9_config {
 };
 
 #define DB9_MAX_PORTS          3
-static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata;
+static struct db9_config db9_cfg[DB9_MAX_PORTS];
 
 module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0);
 MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
@@ -106,6 +106,7 @@ struct db9 {
        struct pardevice *pd;
        int mode;
        int used;
+       int parportno;
        struct mutex mutex;
        char phys[DB9_MAX_DEVICES][32];
 };
@@ -553,54 +554,60 @@ static void db9_close(struct input_dev *dev)
        mutex_unlock(&db9->mutex);
 }
 
-static struct db9 __init *db9_probe(int parport, int mode)
+static void db9_attach(struct parport *pp)
 {
        struct db9 *db9;
        const struct db9_mode_data *db9_mode;
-       struct parport *pp;
        struct pardevice *pd;
        struct input_dev *input_dev;
-       int i, j;
-       int err;
+       int i, j, port_idx;
+       int mode;
+       struct pardev_cb db9_parport_cb;
+
+       for (port_idx = 0; port_idx < DB9_MAX_PORTS; port_idx++) {
+               if (db9_cfg[port_idx].nargs == 0 ||
+                   db9_cfg[port_idx].args[DB9_ARG_PARPORT] < 0)
+                       continue;
+
+               if (db9_cfg[port_idx].args[DB9_ARG_PARPORT] == pp->number)
+                       break;
+       }
+
+       if (port_idx == DB9_MAX_PORTS) {
+               pr_debug("Not using parport%d.\n", pp->number);
+               return;
+       }
+
+       mode = db9_cfg[port_idx].args[DB9_ARG_MODE];
 
        if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) {
                printk(KERN_ERR "db9.c: Bad device type %d\n", mode);
-               err = -EINVAL;
-               goto err_out;
+               return;
        }
 
        db9_mode = &db9_modes[mode];
 
-       pp = parport_find_number(parport);
-       if (!pp) {
-               printk(KERN_ERR "db9.c: no such parport\n");
-               err = -ENODEV;
-               goto err_out;
-       }
-
        if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
                printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
-               err = -EINVAL;
-               goto err_put_pp;
+               return;
        }
 
-       pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+       db9_parport_cb.flags = PARPORT_FLAG_EXCL;
+
+       pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx);
        if (!pd) {
                printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
-               err = -EBUSY;
-               goto err_put_pp;
+               return;
        }
 
        db9 = kzalloc(sizeof(struct db9), GFP_KERNEL);
-       if (!db9) {
-               printk(KERN_ERR "db9.c: Not enough memory\n");
-               err = -ENOMEM;
+       if (!db9)
                goto err_unreg_pardev;
-       }
 
        mutex_init(&db9->mutex);
        db9->pd = pd;
        db9->mode = mode;
+       db9->parportno = pp->number;
        init_timer(&db9->timer);
        db9->timer.data = (long) db9;
        db9->timer.function = db9_timer;
@@ -610,7 +617,6 @@ static struct db9 __init *db9_probe(int parport, int mode)
                db9->dev[i] = input_dev = input_allocate_device();
                if (!input_dev) {
                        printk(KERN_ERR "db9.c: Not enough memory for input device\n");
-                       err = -ENOMEM;
                        goto err_unreg_devs;
                }
 
@@ -639,13 +645,12 @@ static struct db9 __init *db9_probe(int parport, int mode)
                                input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0);
                }
 
-               err = input_register_device(input_dev);
-               if (err)
+               if (input_register_device(input_dev))
                        goto err_free_dev;
        }
 
-       parport_put_port(pp);
-       return db9;
+       db9_base[port_idx] = db9;
+       return;
 
  err_free_dev:
        input_free_device(db9->dev[i]);
@@ -655,15 +660,23 @@ static struct db9 __init *db9_probe(int parport, int mode)
        kfree(db9);
  err_unreg_pardev:
        parport_unregister_device(pd);
- err_put_pp:
-       parport_put_port(pp);
- err_out:
-       return ERR_PTR(err);
 }
 
-static void db9_remove(struct db9 *db9)
+static void db9_detach(struct parport *port)
 {
        int i;
+       struct db9 *db9;
+
+       for (i = 0; i < DB9_MAX_PORTS; i++) {
+               if (db9_base[i] && db9_base[i]->parportno == port->number)
+                       break;
+       }
+
+       if (i == DB9_MAX_PORTS)
+               return;
+
+       db9 = db9_base[i];
+       db9_base[i] = NULL;
 
        for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++)
                input_unregister_device(db9->dev[i]);
@@ -671,11 +684,17 @@ static void db9_remove(struct db9 *db9)
        kfree(db9);
 }
 
+static struct parport_driver db9_parport_driver = {
+       .name = "db9",
+       .match_port = db9_attach,
+       .detach = db9_detach,
+       .devmodel = true,
+};
+
 static int __init db9_init(void)
 {
        int i;
        int have_dev = 0;
-       int err = 0;
 
        for (i = 0; i < DB9_MAX_PORTS; i++) {
                if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0)
@@ -683,37 +702,21 @@ static int __init db9_init(void)
 
                if (db9_cfg[i].nargs < 2) {
                        printk(KERN_ERR "db9.c: Device type must be specified.\n");
-                       err = -EINVAL;
-                       break;
-               }
-
-               db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT],
-                                       db9_cfg[i].args[DB9_ARG_MODE]);
-               if (IS_ERR(db9_base[i])) {
-                       err = PTR_ERR(db9_base[i]);
-                       break;
+                       return -EINVAL;
                }
 
                have_dev = 1;
        }
 
-       if (err) {
-               while (--i >= 0)
-                       if (db9_base[i])
-                               db9_remove(db9_base[i]);
-               return err;
-       }
+       if (!have_dev)
+               return -ENODEV;
 
-       return have_dev ? 0 : -ENODEV;
+       return parport_register_driver(&db9_parport_driver);
 }
 
 static void __exit db9_exit(void)
 {
-       int i;
-
-       for (i = 0; i < DB9_MAX_PORTS; i++)
-               if (db9_base[i])
-                       db9_remove(db9_base[i]);
+       parport_unregister_driver(&db9_parport_driver);
 }
 
 module_init(db9_init);
index e68e497864830f63a9dfa72ee7d5a4948bfb733a..5a672dcac0d8174a151254ac31b591f0189f9d91 100644 (file)
@@ -53,7 +53,7 @@ struct gc_config {
        unsigned int nargs;
 };
 
-static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata;
+static struct gc_config gc_cfg[GC_MAX_PORTS];
 
 module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0);
 MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
@@ -92,6 +92,7 @@ struct gc {
        struct timer_list timer;
        int pad_count[GC_MAX];
        int used;
+       int parportno;
        struct mutex mutex;
 };
 
@@ -304,7 +305,7 @@ static int gc_n64_play_effect(struct input_dev *dev, void *data,
        return 0;
 }
 
-static int __init gc_n64_init_ff(struct input_dev *dev, int i)
+static int gc_n64_init_ff(struct input_dev *dev, int i)
 {
        struct gc_subdev *sdev;
        int err;
@@ -811,7 +812,7 @@ static void gc_close(struct input_dev *dev)
        mutex_unlock(&gc->mutex);
 }
 
-static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
+static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
 {
        struct gc_pad *pad = &gc->pads[idx];
        struct input_dev *input_dev;
@@ -926,46 +927,55 @@ err_free_dev:
        return err;
 }
 
-static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
+static void gc_attach(struct parport *pp)
 {
        struct gc *gc;
-       struct parport *pp;
        struct pardevice *pd;
-       int i;
+       int i, port_idx;
        int count = 0;
-       int err;
+       int *pads, n_pads;
+       struct pardev_cb gc_parport_cb;
+
+       for (port_idx = 0; port_idx < GC_MAX_PORTS; port_idx++) {
+               if (gc_cfg[port_idx].nargs == 0 || gc_cfg[port_idx].args[0] < 0)
+                       continue;
+
+               if (gc_cfg[port_idx].args[0] == pp->number)
+                       break;
+       }
 
-       pp = parport_find_number(parport);
-       if (!pp) {
-               pr_err("no such parport %d\n", parport);
-               err = -EINVAL;
-               goto err_out;
+       if (port_idx == GC_MAX_PORTS) {
+               pr_debug("Not using parport%d.\n", pp->number);
+               return;
        }
+       pads = gc_cfg[port_idx].args + 1;
+       n_pads = gc_cfg[port_idx].nargs - 1;
 
-       pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+       gc_parport_cb.flags = PARPORT_FLAG_EXCL;
+
+       pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb,
+                                       port_idx);
        if (!pd) {
                pr_err("parport busy already - lp.o loaded?\n");
-               err = -EBUSY;
-               goto err_put_pp;
+               return;
        }
 
        gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
        if (!gc) {
                pr_err("Not enough memory\n");
-               err = -ENOMEM;
                goto err_unreg_pardev;
        }
 
        mutex_init(&gc->mutex);
        gc->pd = pd;
+       gc->parportno = pp->number;
        setup_timer(&gc->timer, gc_timer, (long) gc);
 
        for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
                if (!pads[i])
                        continue;
 
-               err = gc_setup_pad(gc, i, pads[i]);
-               if (err)
+               if (gc_setup_pad(gc, i, pads[i]))
                        goto err_unreg_devs;
 
                count++;
@@ -973,12 +983,11 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
 
        if (count == 0) {
                pr_err("No valid devices specified\n");
-               err = -EINVAL;
                goto err_free_gc;
        }
 
-       parport_put_port(pp);
-       return gc;
+       gc_base[port_idx] = gc;
+       return;
 
  err_unreg_devs:
        while (--i >= 0)
@@ -988,15 +997,23 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
        kfree(gc);
  err_unreg_pardev:
        parport_unregister_device(pd);
- err_put_pp:
-       parport_put_port(pp);
- err_out:
-       return ERR_PTR(err);
 }
 
-static void gc_remove(struct gc *gc)
+static void gc_detach(struct parport *port)
 {
        int i;
+       struct gc *gc;
+
+       for (i = 0; i < GC_MAX_PORTS; i++) {
+               if (gc_base[i] && gc_base[i]->parportno == port->number)
+                       break;
+       }
+
+       if (i == GC_MAX_PORTS)
+               return;
+
+       gc = gc_base[i];
+       gc_base[i] = NULL;
 
        for (i = 0; i < GC_MAX_DEVICES; i++)
                if (gc->pads[i].dev)
@@ -1005,11 +1022,17 @@ static void gc_remove(struct gc *gc)
        kfree(gc);
 }
 
+static struct parport_driver gc_parport_driver = {
+       .name = "gamecon",
+       .match_port = gc_attach,
+       .detach = gc_detach,
+       .devmodel = true,
+};
+
 static int __init gc_init(void)
 {
        int i;
        int have_dev = 0;
-       int err = 0;
 
        for (i = 0; i < GC_MAX_PORTS; i++) {
                if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0)
@@ -1017,37 +1040,21 @@ static int __init gc_init(void)
 
                if (gc_cfg[i].nargs < 2) {
                        pr_err("at least one device must be specified\n");
-                       err = -EINVAL;
-                       break;
-               }
-
-               gc_base[i] = gc_probe(gc_cfg[i].args[0],
-                                     gc_cfg[i].args + 1, gc_cfg[i].nargs - 1);
-               if (IS_ERR(gc_base[i])) {
-                       err = PTR_ERR(gc_base[i]);
-                       break;
+                       return -EINVAL;
                }
 
                have_dev = 1;
        }
 
-       if (err) {
-               while (--i >= 0)
-                       if (gc_base[i])
-                               gc_remove(gc_base[i]);
-               return err;
-       }
+       if (!have_dev)
+               return -ENODEV;
 
-       return have_dev ? 0 : -ENODEV;
+       return parport_register_driver(&gc_parport_driver);
 }
 
 static void __exit gc_exit(void)
 {
-       int i;
-
-       for (i = 0; i < GC_MAX_PORTS; i++)
-               if (gc_base[i])
-                       gc_remove(gc_base[i]);
+       parport_unregister_driver(&gc_parport_driver);
 }
 
 module_init(gc_init);
index 891797ad76bccda3ae132e1fc59483b539e522ee..9f5bca26bd2fb85a90ed4fd91bbdcf1a83e84162 100644 (file)
@@ -49,7 +49,7 @@ struct tgfx_config {
        unsigned int nargs;
 };
 
-static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata;
+static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS];
 
 module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0);
 MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
@@ -81,6 +81,7 @@ static struct tgfx {
        char phys[TGFX_MAX_DEVICES][32];
        int sticks;
        int used;
+       int parportno;
        struct mutex sem;
 } *tgfx_base[TGFX_MAX_PORTS];
 
@@ -156,38 +157,48 @@ static void tgfx_close(struct input_dev *dev)
  * tgfx_probe() probes for tg gamepads.
  */
 
-static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
+static void tgfx_attach(struct parport *pp)
 {
        struct tgfx *tgfx;
        struct input_dev *input_dev;
-       struct parport *pp;
        struct pardevice *pd;
-       int i, j;
-       int err;
+       int i, j, port_idx;
+       int *n_buttons, n_devs;
+       struct pardev_cb tgfx_parport_cb;
+
+       for (port_idx = 0; port_idx < TGFX_MAX_PORTS; port_idx++) {
+               if (tgfx_cfg[port_idx].nargs == 0 ||
+                   tgfx_cfg[port_idx].args[0] < 0)
+                       continue;
+               if (tgfx_cfg[port_idx].args[0] == pp->number)
+                       break;
+       }
 
-       pp = parport_find_number(parport);
-       if (!pp) {
-               printk(KERN_ERR "turbografx.c: no such parport\n");
-               err = -EINVAL;
-               goto err_out;
+       if (port_idx == TGFX_MAX_PORTS) {
+               pr_debug("Not using parport%d.\n", pp->number);
+               return;
        }
+       n_buttons = tgfx_cfg[port_idx].args + 1;
+       n_devs = tgfx_cfg[port_idx].nargs - 1;
+
+       tgfx_parport_cb.flags = PARPORT_FLAG_EXCL;
 
-       pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+       pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb,
+                                       port_idx);
        if (!pd) {
-               printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
-               err = -EBUSY;
-               goto err_put_pp;
+               pr_err("parport busy already - lp.o loaded?\n");
+               return;
        }
 
        tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL);
        if (!tgfx) {
                printk(KERN_ERR "turbografx.c: Not enough memory\n");
-               err = -ENOMEM;
                goto err_unreg_pardev;
        }
 
        mutex_init(&tgfx->sem);
        tgfx->pd = pd;
+       tgfx->parportno = pp->number;
        init_timer(&tgfx->timer);
        tgfx->timer.data = (long) tgfx;
        tgfx->timer.function = tgfx_timer;
@@ -198,14 +209,12 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
 
                if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
                        printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
-                       err = -EINVAL;
                        goto err_unreg_devs;
                }
 
                tgfx->dev[i] = input_dev = input_allocate_device();
                if (!input_dev) {
                        printk(KERN_ERR "turbografx.c: Not enough memory for input device\n");
-                       err = -ENOMEM;
                        goto err_unreg_devs;
                }
 
@@ -234,19 +243,17 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
                for (j = 0; j < n_buttons[i]; j++)
                        set_bit(tgfx_buttons[j], input_dev->keybit);
 
-               err = input_register_device(tgfx->dev[i]);
-               if (err)
+               if (input_register_device(tgfx->dev[i]))
                        goto err_free_dev;
        }
 
         if (!tgfx->sticks) {
                printk(KERN_ERR "turbografx.c: No valid devices specified\n");
-               err = -EINVAL;
                goto err_free_tgfx;
         }
 
-       parport_put_port(pp);
-       return tgfx;
+       tgfx_base[port_idx] = tgfx;
+       return;
 
  err_free_dev:
        input_free_device(tgfx->dev[i]);
@@ -258,15 +265,23 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
        kfree(tgfx);
  err_unreg_pardev:
        parport_unregister_device(pd);
- err_put_pp:
-       parport_put_port(pp);
- err_out:
-       return ERR_PTR(err);
 }
 
-static void tgfx_remove(struct tgfx *tgfx)
+static void tgfx_detach(struct parport *port)
 {
        int i;
+       struct tgfx *tgfx;
+
+       for (i = 0; i < TGFX_MAX_PORTS; i++) {
+               if (tgfx_base[i] && tgfx_base[i]->parportno == port->number)
+                       break;
+       }
+
+       if (i == TGFX_MAX_PORTS)
+               return;
+
+       tgfx = tgfx_base[i];
+       tgfx_base[i] = NULL;
 
        for (i = 0; i < TGFX_MAX_DEVICES; i++)
                if (tgfx->dev[i])
@@ -275,11 +290,17 @@ static void tgfx_remove(struct tgfx *tgfx)
        kfree(tgfx);
 }
 
+static struct parport_driver tgfx_parport_driver = {
+       .name = "turbografx",
+       .match_port = tgfx_attach,
+       .detach = tgfx_detach,
+       .devmodel = true,
+};
+
 static int __init tgfx_init(void)
 {
        int i;
        int have_dev = 0;
-       int err = 0;
 
        for (i = 0; i < TGFX_MAX_PORTS; i++) {
                if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0)
@@ -287,38 +308,21 @@ static int __init tgfx_init(void)
 
                if (tgfx_cfg[i].nargs < 2) {
                        printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
-                       err = -EINVAL;
-                       break;
-               }
-
-               tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0],
-                                         tgfx_cfg[i].args + 1,
-                                         tgfx_cfg[i].nargs - 1);
-               if (IS_ERR(tgfx_base[i])) {
-                       err = PTR_ERR(tgfx_base[i]);
-                       break;
+                       return -EINVAL;
                }
 
                have_dev = 1;
        }
 
-       if (err) {
-               while (--i >= 0)
-                       if (tgfx_base[i])
-                               tgfx_remove(tgfx_base[i]);
-               return err;
-       }
+       if (!have_dev)
+               return -ENODEV;
 
-       return have_dev ? 0 : -ENODEV;
+       return parport_register_driver(&tgfx_parport_driver);
 }
 
 static void __exit tgfx_exit(void)
 {
-       int i;
-
-       for (i = 0; i < TGFX_MAX_PORTS; i++)
-               if (tgfx_base[i])
-                       tgfx_remove(tgfx_base[i]);
+       parport_unregister_driver(&tgfx_parport_driver);
 }
 
 module_init(tgfx_init);
index a8bc2fe170dd83e12ff78706f97f9bc32a72e5cd..d88f5dd3c9d9e9a7080cbd9bacecb740e0791488 100644 (file)
@@ -200,35 +200,38 @@ static void walkera0701_close(struct input_dev *dev)
        parport_release(w->pardevice);
 }
 
-static int walkera0701_connect(struct walkera_dev *w, int parport)
+static void walkera0701_attach(struct parport *pp)
 {
-       int error;
+       struct pardev_cb walkera0701_parport_cb;
+       struct walkera_dev *w = &w_dev;
 
-       w->parport = parport_find_number(parport);
-       if (!w->parport) {
-               pr_err("parport %d does not exist\n", parport);
-               return -ENODEV;
+       if (pp->number != walkera0701_pp_no) {
+               pr_debug("Not using parport%d.\n", pp->number);
+               return;
        }
 
-       if (w->parport->irq == -1) {
+       if (pp->irq == -1) {
                pr_err("parport %d does not have interrupt assigned\n",
-                       parport);
-               error = -EINVAL;
-               goto err_put_parport;
+                       pp->number);
+               return;
        }
 
-       w->pardevice = parport_register_device(w->parport, "walkera0701",
-                                   NULL, NULL, walkera0701_irq_handler,
-                                   PARPORT_DEV_EXCL, w);
+       w->parport = pp;
+
+       walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL;
+       walkera0701_parport_cb.irq_func = walkera0701_irq_handler;
+       walkera0701_parport_cb.private = w;
+
+       w->pardevice = parport_register_dev_model(pp, "walkera0701",
+                                                 &walkera0701_parport_cb, 0);
+
        if (!w->pardevice) {
                pr_err("failed to register parport device\n");
-               error = -EIO;
-               goto err_put_parport;
+               return;
        }
 
        if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
                pr_err("failed to negotiate parport mode\n");
-               error = -EIO;
                goto err_unregister_device;
        }
 
@@ -238,7 +241,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
        w->input_dev = input_allocate_device();
        if (!w->input_dev) {
                pr_err("failed to allocate input device\n");
-               error = -ENOMEM;
                goto err_unregister_device;
        }
 
@@ -265,38 +267,46 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
        input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
        input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
 
-       error = input_register_device(w->input_dev);
-       if (error) {
+       if (input_register_device(w->input_dev)) {
                pr_err("failed to register input device\n");
                goto err_free_input_dev;
        }
 
-       return 0;
+       return;
 
 err_free_input_dev:
        input_free_device(w->input_dev);
 err_unregister_device:
        parport_unregister_device(w->pardevice);
-err_put_parport:
-       parport_put_port(w->parport);
-       return error;
 }
 
-static void walkera0701_disconnect(struct walkera_dev *w)
+static void walkera0701_detach(struct parport *port)
 {
+       struct walkera_dev *w = &w_dev;
+
+       if (!w->pardevice || w->parport->number != port->number)
+               return;
+
        input_unregister_device(w->input_dev);
        parport_unregister_device(w->pardevice);
-       parport_put_port(w->parport);
+       w->parport = NULL;
 }
 
+static struct parport_driver walkera0701_parport_driver = {
+       .name = "walkera0701",
+       .match_port = walkera0701_attach,
+       .detach = walkera0701_detach,
+       .devmodel = true,
+};
+
 static int __init walkera0701_init(void)
 {
-       return walkera0701_connect(&w_dev, walkera0701_pp_no);
+       return parport_register_driver(&walkera0701_parport_driver);
 }
 
 static void __exit walkera0701_exit(void)
 {
-       walkera0701_disconnect(&w_dev);
+       parport_unregister_driver(&walkera0701_parport_driver);
 }
 
 module_init(walkera0701_init);
index f8850f9cb33103ccfef4d696389f2b6ddad1249d..fd4100d56d8c5509986be23e40d2af137cd840b1 100644 (file)
@@ -125,6 +125,7 @@ static const struct xpad_device {
        { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
        { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
+       { 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE },
        { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -204,7 +205,7 @@ static const struct xpad_device {
        { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 },
        { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
        { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
-       { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", 0, XTYPE_XBOX360 },
+       { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
        { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
        { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
@@ -242,7 +243,6 @@ static const signed short xpad_btn_triggers[] = {
        -1
 };
 
-
 static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
        BTN_TL, BTN_TR,         /* Button LB/RB */
        BTN_MODE,               /* The big X button */
@@ -328,9 +328,6 @@ struct usb_xpad {
        unsigned char *idata;           /* input data */
        dma_addr_t idata_dma;
 
-       struct urb *bulk_out;
-       unsigned char *bdata;
-
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
@@ -344,7 +341,8 @@ struct usb_xpad {
 
        int mapping;                    /* map d-pad to buttons or to axes */
        int xtype;                      /* type of xbox device */
-       unsigned long led_no;           /* led to lit on xbox360 controllers */
+       int pad_nr;                     /* the order x360 pads were attached */
+       const char *name;               /* name of the device */
 };
 
 /*
@@ -356,7 +354,6 @@ struct usb_xpad {
  *     The used report descriptor was taken from ITO Takayukis website:
  *      http://euc.jp/periphs/xbox-controller.ja.html
  */
-
 static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
 {
        struct input_dev *dev = xpad->dev;
@@ -439,7 +436,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
                input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
                input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
                input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
-       } else {
+       }
+
+       /*
+        * This should be a simple else block. However historically
+        * xbox360w has mapped DPAD to buttons while xbox360 did not. This
+        * made no sense, but now we can not just switch back and have to
+        * support both behaviors.
+        */
+       if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
+           xpad->xtype == XTYPE_XBOX360W) {
                input_report_abs(dev, ABS_HAT0X,
                                 !!(data[2] & 0x08) - !!(data[2] & 0x04));
                input_report_abs(dev, ABS_HAT0Y,
@@ -505,14 +511,12 @@ static void xpad_identify_controller(struct usb_xpad *xpad);
  * 01.1 - Pad state (Bytes 4+) valid
  *
  */
-
 static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
 {
        /* Presence change */
        if (data[0] & 0x08) {
                if (data[1] & 0x80) {
                        xpad->pad_present = 1;
-                       usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
                        /*
                         * Light up the segment corresponding to
                         * controller number.
@@ -674,28 +678,6 @@ exit:
                        __func__, retval);
 }
 
-static void xpad_bulk_out(struct urb *urb)
-{
-       struct usb_xpad *xpad = urb->context;
-       struct device *dev = &xpad->intf->dev;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dev_dbg(dev, "%s - urb shutting down with status: %d\n",
-                       __func__, urb->status);
-               break;
-       default:
-               dev_dbg(dev, "%s - nonzero urb status received: %d\n",
-                       __func__, urb->status);
-       }
-}
-
 static void xpad_irq_out(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -786,84 +768,109 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
        }
 }
 
+static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
+{
+       int retval;
+
+       mutex_lock(&xpad->odata_mutex);
+
+       xpad->odata[0] = 0x08;
+       xpad->odata[1] = 0x00;
+       xpad->odata[2] = 0x0F;
+       xpad->odata[3] = 0xC0;
+       xpad->odata[4] = 0x00;
+       xpad->odata[5] = 0x00;
+       xpad->odata[6] = 0x00;
+       xpad->odata[7] = 0x00;
+       xpad->odata[8] = 0x00;
+       xpad->odata[9] = 0x00;
+       xpad->odata[10] = 0x00;
+       xpad->odata[11] = 0x00;
+       xpad->irq_out->transfer_buffer_length = 12;
+
+       retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+
+       mutex_unlock(&xpad->odata_mutex);
+
+       return retval;
+}
+
 #ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
+       __u16 strong;
+       __u16 weak;
 
-       if (effect->type == FF_RUMBLE) {
-               __u16 strong = effect->u.rumble.strong_magnitude;
-               __u16 weak = effect->u.rumble.weak_magnitude;
-
-               switch (xpad->xtype) {
-
-               case XTYPE_XBOX:
-                       xpad->odata[0] = 0x00;
-                       xpad->odata[1] = 0x06;
-                       xpad->odata[2] = 0x00;
-                       xpad->odata[3] = strong / 256;  /* left actuator */
-                       xpad->odata[4] = 0x00;
-                       xpad->odata[5] = weak / 256;    /* right actuator */
-                       xpad->irq_out->transfer_buffer_length = 6;
-
-                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-               case XTYPE_XBOX360:
-                       xpad->odata[0] = 0x00;
-                       xpad->odata[1] = 0x08;
-                       xpad->odata[2] = 0x00;
-                       xpad->odata[3] = strong / 256;  /* left actuator? */
-                       xpad->odata[4] = weak / 256;    /* right actuator? */
-                       xpad->odata[5] = 0x00;
-                       xpad->odata[6] = 0x00;
-                       xpad->odata[7] = 0x00;
-                       xpad->irq_out->transfer_buffer_length = 8;
-
-                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-               case XTYPE_XBOX360W:
-                       xpad->odata[0] = 0x00;
-                       xpad->odata[1] = 0x01;
-                       xpad->odata[2] = 0x0F;
-                       xpad->odata[3] = 0xC0;
-                       xpad->odata[4] = 0x00;
-                       xpad->odata[5] = strong / 256;
-                       xpad->odata[6] = weak / 256;
-                       xpad->odata[7] = 0x00;
-                       xpad->odata[8] = 0x00;
-                       xpad->odata[9] = 0x00;
-                       xpad->odata[10] = 0x00;
-                       xpad->odata[11] = 0x00;
-                       xpad->irq_out->transfer_buffer_length = 12;
-
-                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-               case XTYPE_XBOXONE:
-                       xpad->odata[0] = 0x09; /* activate rumble */
-                       xpad->odata[1] = 0x08;
-                       xpad->odata[2] = 0x00;
-                       xpad->odata[3] = 0x08; /* continuous effect */
-                       xpad->odata[4] = 0x00; /* simple rumble mode */
-                       xpad->odata[5] = 0x03; /* L and R actuator only */
-                       xpad->odata[6] = 0x00; /* TODO: LT actuator */
-                       xpad->odata[7] = 0x00; /* TODO: RT actuator */
-                       xpad->odata[8] = strong / 256;  /* left actuator */
-                       xpad->odata[9] = weak / 256;    /* right actuator */
-                       xpad->odata[10] = 0x80; /* length of pulse */
-                       xpad->odata[11] = 0x00; /* stop period of pulse */
-                       xpad->irq_out->transfer_buffer_length = 12;
-
-                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-               default:
-                       dev_dbg(&xpad->dev->dev,
-                               "%s - rumble command sent to unsupported xpad type: %d\n",
-                               __func__, xpad->xtype);
-                       return -1;
-               }
+       if (effect->type != FF_RUMBLE)
+               return 0;
+
+       strong = effect->u.rumble.strong_magnitude;
+       weak = effect->u.rumble.weak_magnitude;
+
+       switch (xpad->xtype) {
+       case XTYPE_XBOX:
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x06;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = strong / 256;  /* left actuator */
+               xpad->odata[4] = 0x00;
+               xpad->odata[5] = weak / 256;    /* right actuator */
+               xpad->irq_out->transfer_buffer_length = 6;
+               break;
+
+       case XTYPE_XBOX360:
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x08;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = strong / 256;  /* left actuator? */
+               xpad->odata[4] = weak / 256;    /* right actuator? */
+               xpad->odata[5] = 0x00;
+               xpad->odata[6] = 0x00;
+               xpad->odata[7] = 0x00;
+               xpad->irq_out->transfer_buffer_length = 8;
+               break;
+
+       case XTYPE_XBOX360W:
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x01;
+               xpad->odata[2] = 0x0F;
+               xpad->odata[3] = 0xC0;
+               xpad->odata[4] = 0x00;
+               xpad->odata[5] = strong / 256;
+               xpad->odata[6] = weak / 256;
+               xpad->odata[7] = 0x00;
+               xpad->odata[8] = 0x00;
+               xpad->odata[9] = 0x00;
+               xpad->odata[10] = 0x00;
+               xpad->odata[11] = 0x00;
+               xpad->irq_out->transfer_buffer_length = 12;
+               break;
+
+       case XTYPE_XBOXONE:
+               xpad->odata[0] = 0x09; /* activate rumble */
+               xpad->odata[1] = 0x08;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = 0x08; /* continuous effect */
+               xpad->odata[4] = 0x00; /* simple rumble mode */
+               xpad->odata[5] = 0x03; /* L and R actuator only */
+               xpad->odata[6] = 0x00; /* TODO: LT actuator */
+               xpad->odata[7] = 0x00; /* TODO: RT actuator */
+               xpad->odata[8] = strong / 256;  /* left actuator */
+               xpad->odata[9] = weak / 256;    /* right actuator */
+               xpad->odata[10] = 0x80; /* length of pulse */
+               xpad->odata[11] = 0x00; /* stop period of pulse */
+               xpad->irq_out->transfer_buffer_length = 12;
+               break;
+
+       default:
+               dev_dbg(&xpad->dev->dev,
+                       "%s - rumble command sent to unsupported xpad type: %d\n",
+                       __func__, xpad->xtype);
+               return -EINVAL;
        }
 
-       return 0;
+       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
 }
 
 static int xpad_init_ff(struct usb_xpad *xpad)
@@ -882,6 +889,9 @@ static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
 #include <linux/leds.h>
+#include <linux/idr.h>
+
+static DEFINE_IDA(xpad_pad_seq);
 
 struct xpad_led {
        char name[16];
@@ -890,6 +900,7 @@ struct xpad_led {
 };
 
 /**
+ * set the LEDs on Xbox360 / Wireless Controllers
  * @param command
  *  0: off
  *  1: all blink, then previous setting
@@ -942,10 +953,13 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
        mutex_unlock(&xpad->odata_mutex);
 }
 
+/*
+ * Light up the segment corresponding to the pad number on
+ * Xbox 360 Controllers.
+ */
 static void xpad_identify_controller(struct usb_xpad *xpad)
 {
-       /* Light up the segment corresponding to controller number */
-       xpad_send_led_command(xpad, (xpad->led_no % 4) + 2);
+       xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2);
 }
 
 static void xpad_led_set(struct led_classdev *led_cdev,
@@ -959,7 +973,6 @@ static void xpad_led_set(struct led_classdev *led_cdev,
 
 static int xpad_led_probe(struct usb_xpad *xpad)
 {
-       static atomic_t led_seq = ATOMIC_INIT(-1);
        struct xpad_led *led;
        struct led_classdev *led_cdev;
        int error;
@@ -971,9 +984,13 @@ static int xpad_led_probe(struct usb_xpad *xpad)
        if (!led)
                return -ENOMEM;
 
-       xpad->led_no = atomic_inc_return(&led_seq);
+       xpad->pad_nr = ida_simple_get(&xpad_pad_seq, 0, 0, GFP_KERNEL);
+       if (xpad->pad_nr < 0) {
+               error = xpad->pad_nr;
+               goto err_free_mem;
+       }
 
-       snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no);
+       snprintf(led->name, sizeof(led->name), "xpad%d", xpad->pad_nr);
        led->xpad = xpad;
 
        led_cdev = &led->led_cdev;
@@ -981,16 +998,26 @@ static int xpad_led_probe(struct usb_xpad *xpad)
        led_cdev->brightness_set = xpad_led_set;
 
        error = led_classdev_register(&xpad->udev->dev, led_cdev);
-       if (error) {
-               kfree(led);
-               xpad->led = NULL;
-               return error;
-       }
+       if (error)
+               goto err_free_id;
 
-       /* Light up the segment corresponding to controller number */
-       xpad_identify_controller(xpad);
+       if (xpad->xtype == XTYPE_XBOX360) {
+               /*
+                * Light up the segment corresponding to controller
+                * number on wired devices. On wireless we'll do that
+                * when they respond to "presence" packet.
+                */
+               xpad_identify_controller(xpad);
+       }
 
        return 0;
+
+err_free_id:
+       ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
+err_free_mem:
+       kfree(led);
+       xpad->led = NULL;
+       return error;
 }
 
 static void xpad_led_disconnect(struct usb_xpad *xpad)
@@ -999,6 +1026,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
 
        if (xpad_led) {
                led_classdev_unregister(&xpad_led->led_cdev);
+               ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
                kfree(xpad_led);
        }
 }
@@ -1008,7 +1036,6 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { }
 static void xpad_identify_controller(struct usb_xpad *xpad) { }
 #endif
 
-
 static int xpad_open(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -1068,11 +1095,107 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
        }
 }
 
+static void xpad_deinit_input(struct usb_xpad *xpad)
+{
+       xpad_led_disconnect(xpad);
+       input_unregister_device(xpad->dev);
+}
+
+static int xpad_init_input(struct usb_xpad *xpad)
+{
+       struct input_dev *input_dev;
+       int i, error;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       xpad->dev = input_dev;
+       input_dev->name = xpad->name;
+       input_dev->phys = xpad->phys;
+       usb_to_input_id(xpad->udev, &input_dev->id);
+       input_dev->dev.parent = &xpad->intf->dev;
+
+       input_set_drvdata(input_dev, xpad);
+
+       input_dev->open = xpad_open;
+       input_dev->close = xpad_close;
+
+       __set_bit(EV_KEY, input_dev->evbit);
+
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               __set_bit(EV_ABS, input_dev->evbit);
+               /* set up axes */
+               for (i = 0; xpad_abs[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs[i]);
+       }
+
+       /* set up standard buttons */
+       for (i = 0; xpad_common_btn[i] >= 0; i++)
+               __set_bit(xpad_common_btn[i], input_dev->keybit);
+
+       /* set up model-specific ones */
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+           xpad->xtype == XTYPE_XBOXONE) {
+               for (i = 0; xpad360_btn[i] >= 0; i++)
+                       __set_bit(xpad360_btn[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_btn[i] >= 0; i++)
+                       __set_bit(xpad_btn[i], input_dev->keybit);
+       }
+
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               for (i = 0; xpad_btn_pad[i] >= 0; i++)
+                       __set_bit(xpad_btn_pad[i], input_dev->keybit);
+       }
+
+       /*
+        * This should be a simple else block. However historically
+        * xbox360w has mapped DPAD to buttons while xbox360 did not. This
+        * made no sense, but now we can not just switch back and have to
+        * support both behaviors.
+        */
+       if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
+           xpad->xtype == XTYPE_XBOX360W) {
+               for (i = 0; xpad_abs_pad[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+       }
+
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               for (i = 0; xpad_btn_triggers[i] >= 0; i++)
+                       __set_bit(xpad_btn_triggers[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_abs_triggers[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
+       }
+
+       error = xpad_init_ff(xpad);
+       if (error)
+               goto err_free_input;
+
+       error = xpad_led_probe(xpad);
+       if (error)
+               goto err_destroy_ff;
+
+       error = input_register_device(xpad->dev);
+       if (error)
+               goto err_disconnect_led;
+
+       return 0;
+
+err_disconnect_led:
+       xpad_led_disconnect(xpad);
+err_destroy_ff:
+       input_ff_destroy(input_dev);
+err_free_input:
+       input_free_device(input_dev);
+       return error;
+}
+
 static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct usb_xpad *xpad;
-       struct input_dev *input_dev;
        struct usb_endpoint_descriptor *ep_irq_in;
        int ep_irq_in_idx;
        int i, error;
@@ -1094,29 +1217,30 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        }
 
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!xpad || !input_dev) {
-               error = -ENOMEM;
-               goto fail1;
-       }
+       if (!xpad)
+               return -ENOMEM;
+
+       usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
+       strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
 
        xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
                                         GFP_KERNEL, &xpad->idata_dma);
        if (!xpad->idata) {
                error = -ENOMEM;
-               goto fail1;
+               goto err_free_mem;
        }
 
        xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
        if (!xpad->irq_in) {
                error = -ENOMEM;
-               goto fail2;
+               goto err_free_idata;
        }
 
        xpad->udev = udev;
        xpad->intf = intf;
        xpad->mapping = xpad_device[i].mapping;
        xpad->xtype = xpad_device[i].xtype;
+       xpad->name = xpad_device[i].name;
 
        if (xpad->xtype == XTYPE_UNKNOWN) {
                if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
@@ -1124,8 +1248,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                                xpad->xtype = XTYPE_XBOX360W;
                        else
                                xpad->xtype = XTYPE_XBOX360;
-               } else
+               } else {
                        xpad->xtype = XTYPE_XBOX;
+               }
 
                if (dpad_to_buttons)
                        xpad->mapping |= MAP_DPAD_TO_BUTTONS;
@@ -1135,70 +1260,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        xpad->mapping |= MAP_STICKS_TO_NULL;
        }
 
-       xpad->dev = input_dev;
-       usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
-       strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
-
-       input_dev->name = xpad_device[i].name;
-       input_dev->phys = xpad->phys;
-       usb_to_input_id(udev, &input_dev->id);
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, xpad);
-
-       input_dev->open = xpad_open;
-       input_dev->close = xpad_close;
-
-       input_dev->evbit[0] = BIT_MASK(EV_KEY);
-
-       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
-               input_dev->evbit[0] |= BIT_MASK(EV_ABS);
-               /* set up axes */
-               for (i = 0; xpad_abs[i] >= 0; i++)
-                       xpad_set_up_abs(input_dev, xpad_abs[i]);
-       }
-
-       /* set up standard buttons */
-       for (i = 0; xpad_common_btn[i] >= 0; i++)
-               __set_bit(xpad_common_btn[i], input_dev->keybit);
-
-       /* set up model-specific ones */
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
-           xpad->xtype == XTYPE_XBOXONE) {
-               for (i = 0; xpad360_btn[i] >= 0; i++)
-                       __set_bit(xpad360_btn[i], input_dev->keybit);
-       } else {
-               for (i = 0; xpad_btn[i] >= 0; i++)
-                       __set_bit(xpad_btn[i], input_dev->keybit);
-       }
-
-       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-               for (i = 0; xpad_btn_pad[i] >= 0; i++)
-                       __set_bit(xpad_btn_pad[i], input_dev->keybit);
-       } else {
-               for (i = 0; xpad_abs_pad[i] >= 0; i++)
-                       xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
-       }
-
-       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
-               for (i = 0; xpad_btn_triggers[i] >= 0; i++)
-                       __set_bit(xpad_btn_triggers[i], input_dev->keybit);
-       } else {
-               for (i = 0; xpad_abs_triggers[i] >= 0; i++)
-                       xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
-       }
-
        error = xpad_init_output(intf, xpad);
        if (error)
-               goto fail3;
-
-       error = xpad_init_ff(xpad);
-       if (error)
-               goto fail4;
-
-       error = xpad_led_probe(xpad);
-       if (error)
-               goto fail5;
+               goto err_free_in_urb;
 
        /* Xbox One controller has in/out endpoints swapped. */
        ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
@@ -1211,59 +1275,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        xpad->irq_in->transfer_dma = xpad->idata_dma;
        xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       error = input_register_device(xpad->dev);
-       if (error)
-               goto fail6;
-
        usb_set_intfdata(intf, xpad);
 
-       if (xpad->xtype == XTYPE_XBOX360W) {
-               /*
-                * Setup the message to set the LEDs on the
-                * controller when it shows up
-                */
-               xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
-               if (!xpad->bulk_out) {
-                       error = -ENOMEM;
-                       goto fail7;
-               }
-
-               xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
-               if (!xpad->bdata) {
-                       error = -ENOMEM;
-                       goto fail8;
-               }
-
-               xpad->bdata[2] = 0x08;
-               switch (intf->cur_altsetting->desc.bInterfaceNumber) {
-               case 0:
-                       xpad->bdata[3] = 0x42;
-                       break;
-               case 2:
-                       xpad->bdata[3] = 0x43;
-                       break;
-               case 4:
-                       xpad->bdata[3] = 0x44;
-                       break;
-               case 6:
-                       xpad->bdata[3] = 0x45;
-               }
-
-               ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
-               if (usb_endpoint_is_bulk_out(ep_irq_in)) {
-                       usb_fill_bulk_urb(xpad->bulk_out, udev,
-                                         usb_sndbulkpipe(udev,
-                                                         ep_irq_in->bEndpointAddress),
-                                         xpad->bdata, XPAD_PKT_LEN,
-                                         xpad_bulk_out, xpad);
-               } else {
-                       usb_fill_int_urb(xpad->bulk_out, udev,
-                                        usb_sndintpipe(udev,
-                                                       ep_irq_in->bEndpointAddress),
-                                        xpad->bdata, XPAD_PKT_LEN,
-                                        xpad_bulk_out, xpad, 0);
-               }
+       error = xpad_init_input(xpad);
+       if (error)
+               goto err_deinit_output;
 
+       if (xpad->xtype == XTYPE_XBOX360W) {
                /*
                 * Submit the int URB immediately rather than waiting for open
                 * because we get status messages from the device whether
@@ -1274,22 +1292,32 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                xpad->irq_in->dev = xpad->udev;
                error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
                if (error)
-                       goto fail9;
-       }
+                       goto err_deinit_input;
 
+               /*
+                * Send presence packet.
+                * This will force the controller to resend connection packets.
+                * This is useful in the case we activate the module after the
+                * adapter has been plugged in, as it won't automatically
+                * send us info about the controllers.
+                */
+               error = xpad_inquiry_pad_presence(xpad);
+               if (error)
+                       goto err_kill_in_urb;
+       }
        return 0;
 
- fail9:        kfree(xpad->bdata);
fail8:        usb_free_urb(xpad->bulk_out);
- fail7:        input_unregister_device(input_dev);
-       input_dev = NULL;
- fail6:        xpad_led_disconnect(xpad);
- fail5:        if (input_dev)
-               input_ff_destroy(input_dev);
fail4:        xpad_deinit_output(xpad);
- fail3:        usb_free_urb(xpad->irq_in);
fail2:        usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
- fail1:        input_free_device(input_dev);
+err_kill_in_urb:
      usb_kill_urb(xpad->irq_in);
+err_deinit_input:
+       xpad_deinit_input(xpad);
+err_deinit_output:
+       xpad_deinit_output(xpad);
+err_free_in_urb:
      usb_free_urb(xpad->irq_in);
+err_free_idata:
+       usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+err_free_mem:
        kfree(xpad);
        return error;
 
@@ -1299,13 +1327,10 @@ static void xpad_disconnect(struct usb_interface *intf)
 {
        struct usb_xpad *xpad = usb_get_intfdata (intf);
 
-       xpad_led_disconnect(xpad);
-       input_unregister_device(xpad->dev);
+       xpad_deinit_input(xpad);
        xpad_deinit_output(xpad);
 
        if (xpad->xtype == XTYPE_XBOX360W) {
-               usb_kill_urb(xpad->bulk_out);
-               usb_free_urb(xpad->bulk_out);
                usb_kill_urb(xpad->irq_in);
        }
 
@@ -1313,7 +1338,6 @@ static void xpad_disconnect(struct usb_interface *intf)
        usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
                        xpad->idata, xpad->idata_dma);
 
-       kfree(xpad->bdata);
        kfree(xpad);
 
        usb_set_intfdata(intf, NULL);
index 2e80107ff630384739ec23d497e9d14321be25c5..ddd8148d51d70cf5994c53190110ae9c35adadfb 100644 (file)
@@ -516,7 +516,7 @@ config KEYBOARD_SAMSUNG
          module will be called samsung-keypad.
 
 config KEYBOARD_GOLDFISH_EVENTS
-       depends on GOLDFISH
+       depends on GOLDFISH || COMPILE_TEST
        tristate "Generic Input Event device for Goldfish"
        help
          Say Y here to get an input event device for the Goldfish virtual
index 9d517ca7eb5aad432249d34ed8a710588510bd21..bef317ff7352ffd73885ea6a11efd58efba9663d 100644 (file)
@@ -341,8 +341,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
        const struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
-       int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
+       int state = gpio_get_value_cansleep(button->gpio);
 
+       if (state < 0) {
+               dev_err(input->dev.parent, "failed to get gpio state\n");
+               return;
+       }
+
+       state = (state ? 1 : 0) ^ button->active_low;
        if (type == EV_ABS) {
                if (state)
                        input_event(input, type, button->code, button->value);
index 870cfa6e2c44ed6791782401bb098096c4d052f4..62bdb1d48c49dbd990ce37f2da335ee8d60b472d 100644 (file)
@@ -40,10 +40,36 @@ struct gpio_keys_polled_dev {
        struct input_polled_dev *poll_dev;
        struct device *dev;
        const struct gpio_keys_platform_data *pdata;
+       unsigned long rel_axis_seen[BITS_TO_LONGS(REL_CNT)];
+       unsigned long abs_axis_seen[BITS_TO_LONGS(ABS_CNT)];
        struct gpio_keys_button_data data[0];
 };
 
-static void gpio_keys_polled_check_state(struct input_dev *input,
+static void gpio_keys_button_event(struct input_polled_dev *dev,
+                                  struct gpio_keys_button *button,
+                                  int state)
+{
+       struct gpio_keys_polled_dev *bdev = dev->private;
+       struct input_dev *input = dev->input;
+       unsigned int type = button->type ?: EV_KEY;
+
+       if (type == EV_REL) {
+               if (state) {
+                       input_event(input, type, button->code, button->value);
+                       __set_bit(button->code, bdev->rel_axis_seen);
+               }
+       } else if (type == EV_ABS) {
+               if (state) {
+                       input_event(input, type, button->code, button->value);
+                       __set_bit(button->code, bdev->abs_axis_seen);
+               }
+       } else {
+               input_event(input, type, button->code, state);
+               input_sync(input);
+       }
+}
+
+static void gpio_keys_polled_check_state(struct input_polled_dev *dev,
                                         struct gpio_keys_button *button,
                                         struct gpio_keys_button_data *bdata)
 {
@@ -54,11 +80,9 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
        else
                state = !!gpiod_get_value(button->gpiod);
 
-       if (state != bdata->last_state) {
-               unsigned int type = button->type ?: EV_KEY;
+       gpio_keys_button_event(dev, button, state);
 
-               input_event(input, type, button->code, state);
-               input_sync(input);
+       if (state != bdata->last_state) {
                bdata->count = 0;
                bdata->last_state = state;
        }
@@ -71,15 +95,33 @@ static void gpio_keys_polled_poll(struct input_polled_dev *dev)
        struct input_dev *input = dev->input;
        int i;
 
+       memset(bdev->rel_axis_seen, 0, sizeof(bdev->rel_axis_seen));
+       memset(bdev->abs_axis_seen, 0, sizeof(bdev->abs_axis_seen));
+
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button_data *bdata = &bdev->data[i];
 
-               if (bdata->count < bdata->threshold)
+               if (bdata->count < bdata->threshold) {
                        bdata->count++;
-               else
-                       gpio_keys_polled_check_state(input, &pdata->buttons[i],
+                       gpio_keys_button_event(dev, &pdata->buttons[i],
+                                              bdata->last_state);
+               } else {
+                       gpio_keys_polled_check_state(dev, &pdata->buttons[i],
                                                     bdata);
+               }
+       }
+
+       for_each_set_bit(i, input->relbit, REL_CNT) {
+               if (!test_bit(i, bdev->rel_axis_seen))
+                       input_event(input, EV_REL, i, 0);
+       }
+
+       for_each_set_bit(i, input->absbit, ABS_CNT) {
+               if (!test_bit(i, bdev->abs_axis_seen))
+                       input_event(input, EV_ABS, i, 0);
        }
+
+       input_sync(input);
 }
 
 static void gpio_keys_polled_open(struct input_polled_dev *dev)
@@ -152,6 +194,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                                             &button->type))
                        button->type = EV_KEY;
 
+               if (fwnode_property_read_u32(child, "linux,input-value",
+                                            (u32 *)&button->value))
+                       button->value = 1;
+
                button->wakeup =
                        fwnode_property_read_bool(child, "wakeup-source") ||
                        /* legacy name */
@@ -168,6 +214,25 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
        return pdata;
 }
 
+static void gpio_keys_polled_set_abs_params(struct input_dev *input,
+       const struct gpio_keys_platform_data *pdata, unsigned int code)
+{
+       int i, min = 0, max = 0;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               struct gpio_keys_button *button = &pdata->buttons[i];
+
+               if (button->type != EV_ABS || button->code != code)
+                       continue;
+
+               if (button->value < min)
+                       min = button->value;
+               if (button->value > max)
+                       max = button->value;
+       }
+       input_set_abs_params(input, code, min, max, 0, 0);
+}
+
 static const struct of_device_id gpio_keys_polled_of_match[] = {
        { .compatible = "gpio-keys-polled", },
        { },
@@ -274,6 +339,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                                                pdata->poll_interval);
 
                input_set_capability(input, type, button->code);
+               if (type == EV_ABS)
+                       gpio_keys_polled_set_abs_params(input, pdata,
+                                                       button->code);
        }
 
        bdev->poll_dev = poll_dev;
@@ -290,9 +358,11 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
        /* report initial state of the buttons */
        for (i = 0; i < pdata->nbuttons; i++)
-               gpio_keys_polled_check_state(input, &pdata->buttons[i],
+               gpio_keys_polled_check_state(poll_dev, &pdata->buttons[i],
                                             &bdev->data[i]);
 
+       input_sync(input);
+
        return 0;
 }
 
index c7d5b1666fc33ba1418c35d6673b171fca8eaacf..8567ee47761e111b31f7c8270bdc6414de6668a1 100644 (file)
@@ -54,7 +54,7 @@
 /**
  * struct ske_keypad  - data structure used by keypad driver
  * @irq:       irq no
- * @reg_base:  ske regsiters base address
+ * @reg_base:  ske registers base address
  * @input:     pointer to input device object
  * @board:     keypad platform device
  * @keymap:    matrix scan code table for keycodes
index 78fd24ca3813d988d0bc21a70469e4ed7aa6f53d..9adf13a5864adaa94052b3a01d408658e4150123 100644 (file)
@@ -110,8 +110,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENOMEM;
 
-       pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");;
-
+       pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
        if (!pdata->snvs) {
                dev_err(&pdev->dev, "Can't get snvs syscon\n");
                return -ENODEV;
index f97c73bd14f8f6427534ebee8e8b502f7b527299..acc5394afb0343a62a4502f24251898d216daf09 100644 (file)
@@ -517,7 +517,8 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
        if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
                kbc->use_ghost_filter = true;
 
-       if (of_find_property(np, "nvidia,wakeup-source", NULL))
+       if (of_property_read_bool(np, "wakeup-source") ||
+           of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */
                kbc->wakeup = true;
 
        if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
@@ -705,7 +706,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
        input_set_drvdata(kbc->idev, kbc);
 
        err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr,
-                         IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
+                              IRQF_TRIGGER_HIGH, pdev->name, kbc);
        if (err) {
                dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
                return err;
index 906dd1b25e41b7efc0aa12f70e37bb977fa61c76..d6d16fa782815481e04609771b09b32e862ce679 100644 (file)
@@ -94,11 +94,11 @@ config INPUT_BMA150
          module will be called bma150.
 
 config INPUT_E3X0_BUTTON
-       tristate "NI Ettus Research USRP E3x0 Button support."
+       tristate "NI Ettus Research USRP E3xx Button support."
        default n
        help
          Say Y here to enable support for the NI Ettus Research
-         USRP E3x0 Button.
+         USRP E3xx Button.
 
          To compile this driver as a module, choose M here: the
          module will be called e3x0_button.
@@ -599,11 +599,11 @@ config INPUT_DA9055_ONKEY
          will be called da9055_onkey.
 
 config INPUT_DA9063_ONKEY
-       tristate "Dialog DA9063 OnKey"
-       depends on MFD_DA9063
+       tristate "Dialog DA9062/63 OnKey"
+       depends on MFD_DA9063 || MFD_DA9062
        help
-         Support the ONKEY of Dialog DA9063 Power Management IC as an
-         input device reporting power button statue.
+         Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
+         as an input device capable of reporting the power button status.
 
          To compile this driver as a module, choose M here: the module
          will be called da9063_onkey.
index 189bdc8e91a5d2d116cda4d429ca8474eb071c26..2f047738bc0bd85f1ff21459a0b9709fa6a422b9 100644 (file)
@@ -85,15 +85,6 @@ static int ad714x_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int ad714x_i2c_remove(struct i2c_client *client)
-{
-       struct ad714x_chip *chip = i2c_get_clientdata(client);
-
-       ad714x_remove(chip);
-
-       return 0;
-}
-
 static const struct i2c_device_id ad714x_id[] = {
        { "ad7142_captouch", 0 },
        { "ad7143_captouch", 0 },
@@ -110,7 +101,6 @@ static struct i2c_driver ad714x_i2c_driver = {
                .pm   = &ad714x_i2c_pm,
        },
        .probe    = ad714x_i2c_probe,
-       .remove   = ad714x_i2c_remove,
        .id_table = ad714x_id,
 };
 
index fea315e76bc8485927652e58198396f27c470078..aac910326447cfcf39a1ae611cdb435150bbd5d4 100644 (file)
@@ -101,22 +101,12 @@ static int ad714x_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int ad714x_spi_remove(struct spi_device *spi)
-{
-       struct ad714x_chip *chip = spi_get_drvdata(spi);
-
-       ad714x_remove(chip);
-
-       return 0;
-}
-
 static struct spi_driver ad714x_spi_driver = {
        .driver = {
                .name   = "ad714x_captouch",
                .pm     = &ad714x_spi_pm,
        },
        .probe          = ad714x_spi_probe,
-       .remove         = ad714x_spi_remove,
 };
 
 module_spi_driver(ad714x_spi_driver);
index 7a61e9ee682cff92c7b445c8fbc660f31286088b..84b51dd51f6e9147396d43bc002833e670d24764 100644 (file)
@@ -960,13 +960,12 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-#define MAX_DEVICE_NUM 8
 struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                                 ad714x_read_t read, ad714x_write_t write)
 {
-       int i, alloc_idx;
+       int i;
        int error;
-       struct input_dev *input[MAX_DEVICE_NUM];
+       struct input_dev *input;
 
        struct ad714x_platform_data *plat_data = dev_get_platdata(dev);
        struct ad714x_chip *ad714x;
@@ -982,25 +981,25 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
        if (irq <= 0) {
                dev_err(dev, "IRQ not configured!\n");
                error = -EINVAL;
-               goto err_out;
+               return ERR_PTR(error);
        }
 
        if (dev_get_platdata(dev) == NULL) {
                dev_err(dev, "platform data for ad714x doesn't exist\n");
                error = -EINVAL;
-               goto err_out;
+               return ERR_PTR(error);
        }
 
-       ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) +
-                        sizeof(*sd_drv) * plat_data->slider_num +
-                        sizeof(*wl_drv) * plat_data->wheel_num +
-                        sizeof(*tp_drv) * plat_data->touchpad_num +
-                        sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL);
+       ad714x = devm_kzalloc(dev, sizeof(*ad714x) + sizeof(*ad714x->sw) +
+                                  sizeof(*sd_drv) * plat_data->slider_num +
+                                  sizeof(*wl_drv) * plat_data->wheel_num +
+                                  sizeof(*tp_drv) * plat_data->touchpad_num +
+                                  sizeof(*bt_drv) * plat_data->button_num,
+                             GFP_KERNEL);
        if (!ad714x) {
                error = -ENOMEM;
-               goto err_out;
+               return ERR_PTR(error);
        }
-
        ad714x->hw = plat_data;
 
        drv_mem = ad714x + 1;
@@ -1022,47 +1021,40 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
 
        error = ad714x_hw_detect(ad714x);
        if (error)
-               goto err_free_mem;
+               return ERR_PTR(error);
 
        /* initialize and request sw/hw resources */
 
        ad714x_hw_init(ad714x);
        mutex_init(&ad714x->mutex);
 
-       /*
-        * Allocate and register AD714X input device
-        */
-       alloc_idx = 0;
-
        /* a slider uses one input_dev instance */
        if (ad714x->hw->slider_num > 0) {
                struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
 
                for (i = 0; i < ad714x->hw->slider_num; i++) {
-                       sd_drv[i].input = input[alloc_idx] = input_allocate_device();
-                       if (!input[alloc_idx]) {
-                               error = -ENOMEM;
-                               goto err_free_dev;
-                       }
-
-                       __set_bit(EV_ABS, input[alloc_idx]->evbit);
-                       __set_bit(EV_KEY, input[alloc_idx]->evbit);
-                       __set_bit(ABS_X, input[alloc_idx]->absbit);
-                       __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
-                       input_set_abs_params(input[alloc_idx],
+                       input = devm_input_allocate_device(dev);
+                       if (!input)
+                               return ERR_PTR(-ENOMEM);
+
+                       __set_bit(EV_ABS, input->evbit);
+                       __set_bit(EV_KEY, input->evbit);
+                       __set_bit(ABS_X, input->absbit);
+                       __set_bit(BTN_TOUCH, input->keybit);
+                       input_set_abs_params(input,
                                ABS_X, 0, sd_plat->max_coord, 0, 0);
 
-                       input[alloc_idx]->id.bustype = bus_type;
-                       input[alloc_idx]->id.product = ad714x->product;
-                       input[alloc_idx]->id.version = ad714x->version;
-                       input[alloc_idx]->name = "ad714x_captouch_slider";
-                       input[alloc_idx]->dev.parent = dev;
+                       input->id.bustype = bus_type;
+                       input->id.product = ad714x->product;
+                       input->id.version = ad714x->version;
+                       input->name = "ad714x_captouch_slider";
+                       input->dev.parent = dev;
 
-                       error = input_register_device(input[alloc_idx]);
+                       error = input_register_device(input);
                        if (error)
-                               goto err_free_dev;
+                               return ERR_PTR(error);
 
-                       alloc_idx++;
+                       sd_drv[i].input = input;
                }
        }
 
@@ -1071,30 +1063,28 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
 
                for (i = 0; i < ad714x->hw->wheel_num; i++) {
-                       wl_drv[i].input = input[alloc_idx] = input_allocate_device();
-                       if (!input[alloc_idx]) {
-                               error = -ENOMEM;
-                               goto err_free_dev;
-                       }
-
-                       __set_bit(EV_KEY, input[alloc_idx]->evbit);
-                       __set_bit(EV_ABS, input[alloc_idx]->evbit);
-                       __set_bit(ABS_WHEEL, input[alloc_idx]->absbit);
-                       __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
-                       input_set_abs_params(input[alloc_idx],
+                       input = devm_input_allocate_device(dev);
+                       if (!input)
+                               return ERR_PTR(-ENOMEM);
+
+                       __set_bit(EV_KEY, input->evbit);
+                       __set_bit(EV_ABS, input->evbit);
+                       __set_bit(ABS_WHEEL, input->absbit);
+                       __set_bit(BTN_TOUCH, input->keybit);
+                       input_set_abs_params(input,
                                ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
 
-                       input[alloc_idx]->id.bustype = bus_type;
-                       input[alloc_idx]->id.product = ad714x->product;
-                       input[alloc_idx]->id.version = ad714x->version;
-                       input[alloc_idx]->name = "ad714x_captouch_wheel";
-                       input[alloc_idx]->dev.parent = dev;
+                       input->id.bustype = bus_type;
+                       input->id.product = ad714x->product;
+                       input->id.version = ad714x->version;
+                       input->name = "ad714x_captouch_wheel";
+                       input->dev.parent = dev;
 
-                       error = input_register_device(input[alloc_idx]);
+                       error = input_register_device(input);
                        if (error)
-                               goto err_free_dev;
+                               return ERR_PTR(error);
 
-                       alloc_idx++;
+                       wl_drv[i].input = input;
                }
        }
 
@@ -1103,33 +1093,31 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
 
                for (i = 0; i < ad714x->hw->touchpad_num; i++) {
-                       tp_drv[i].input = input[alloc_idx] = input_allocate_device();
-                       if (!input[alloc_idx]) {
-                               error = -ENOMEM;
-                               goto err_free_dev;
-                       }
-
-                       __set_bit(EV_ABS, input[alloc_idx]->evbit);
-                       __set_bit(EV_KEY, input[alloc_idx]->evbit);
-                       __set_bit(ABS_X, input[alloc_idx]->absbit);
-                       __set_bit(ABS_Y, input[alloc_idx]->absbit);
-                       __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
-                       input_set_abs_params(input[alloc_idx],
+                       input = devm_input_allocate_device(dev);
+                       if (!input)
+                               return ERR_PTR(-ENOMEM);
+
+                       __set_bit(EV_ABS, input->evbit);
+                       __set_bit(EV_KEY, input->evbit);
+                       __set_bit(ABS_X, input->absbit);
+                       __set_bit(ABS_Y, input->absbit);
+                       __set_bit(BTN_TOUCH, input->keybit);
+                       input_set_abs_params(input,
                                ABS_X, 0, tp_plat->x_max_coord, 0, 0);
-                       input_set_abs_params(input[alloc_idx],
+                       input_set_abs_params(input,
                                ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
 
-                       input[alloc_idx]->id.bustype = bus_type;
-                       input[alloc_idx]->id.product = ad714x->product;
-                       input[alloc_idx]->id.version = ad714x->version;
-                       input[alloc_idx]->name = "ad714x_captouch_pad";
-                       input[alloc_idx]->dev.parent = dev;
+                       input->id.bustype = bus_type;
+                       input->id.product = ad714x->product;
+                       input->id.version = ad714x->version;
+                       input->name = "ad714x_captouch_pad";
+                       input->dev.parent = dev;
 
-                       error = input_register_device(input[alloc_idx]);
+                       error = input_register_device(input);
                        if (error)
-                               goto err_free_dev;
+                               return ERR_PTR(error);
 
-                       alloc_idx++;
+                       tp_drv[i].input = input;
                }
        }
 
@@ -1137,82 +1125,44 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
        if (ad714x->hw->button_num > 0) {
                struct ad714x_button_plat *bt_plat = ad714x->hw->button;
 
-               input[alloc_idx] = input_allocate_device();
-               if (!input[alloc_idx]) {
+               input = devm_input_allocate_device(dev);
+               if (!input) {
                        error = -ENOMEM;
-                       goto err_free_dev;
+                       return ERR_PTR(error);
                }
 
-               __set_bit(EV_KEY, input[alloc_idx]->evbit);
+               __set_bit(EV_KEY, input->evbit);
                for (i = 0; i < ad714x->hw->button_num; i++) {
-                       bt_drv[i].input = input[alloc_idx];
-                       __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit);
+                       bt_drv[i].input = input;
+                       __set_bit(bt_plat[i].keycode, input->keybit);
                }
 
-               input[alloc_idx]->id.bustype = bus_type;
-               input[alloc_idx]->id.product = ad714x->product;
-               input[alloc_idx]->id.version = ad714x->version;
-               input[alloc_idx]->name = "ad714x_captouch_button";
-               input[alloc_idx]->dev.parent = dev;
+               input->id.bustype = bus_type;
+               input->id.product = ad714x->product;
+               input->id.version = ad714x->version;
+               input->name = "ad714x_captouch_button";
+               input->dev.parent = dev;
 
-               error = input_register_device(input[alloc_idx]);
+               error = input_register_device(input);
                if (error)
-                       goto err_free_dev;
-
-               alloc_idx++;
+                       return ERR_PTR(error);
        }
 
        irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING;
        irqflags |= IRQF_ONESHOT;
 
-       error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
-                                    irqflags, "ad714x_captouch", ad714x);
+       error = devm_request_threaded_irq(dev, ad714x->irq, NULL,
+                                         ad714x_interrupt_thread,
+                                         irqflags, "ad714x_captouch", ad714x);
        if (error) {
                dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
-               goto err_unreg_dev;
+               return ERR_PTR(error);
        }
 
        return ad714x;
-
- err_free_dev:
-       dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx);
-       input_free_device(input[alloc_idx]);
- err_unreg_dev:
-       while (--alloc_idx >= 0)
-               input_unregister_device(input[alloc_idx]);
- err_free_mem:
-       kfree(ad714x);
- err_out:
-       return ERR_PTR(error);
 }
 EXPORT_SYMBOL(ad714x_probe);
 
-void ad714x_remove(struct ad714x_chip *ad714x)
-{
-       struct ad714x_platform_data *hw = ad714x->hw;
-       struct ad714x_driver_data *sw = ad714x->sw;
-       int i;
-
-       free_irq(ad714x->irq, ad714x);
-
-       /* unregister and free all input devices */
-
-       for (i = 0; i < hw->slider_num; i++)
-               input_unregister_device(sw->slider[i].input);
-
-       for (i = 0; i < hw->wheel_num; i++)
-               input_unregister_device(sw->wheel[i].input);
-
-       for (i = 0; i < hw->touchpad_num; i++)
-               input_unregister_device(sw->touchpad[i].input);
-
-       if (hw->button_num)
-               input_unregister_device(sw->button[0].input);
-
-       kfree(ad714x);
-}
-EXPORT_SYMBOL(ad714x_remove);
-
 #ifdef CONFIG_PM
 int ad714x_disable(struct ad714x_chip *ad714x)
 {
index 3c85455aa66d23329d3605fb367d400d320e4976..5d65d303b9bfa9d41f936ffd6908fe4f6f38ce8d 100644 (file)
@@ -50,6 +50,5 @@ int ad714x_disable(struct ad714x_chip *ad714x);
 int ad714x_enable(struct ad714x_chip *ad714x);
 struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                                 ad714x_read_t read, ad714x_write_t write);
-void ad714x_remove(struct ad714x_chip *ad714x);
 
 #endif
index f577585ef999af29425531b9cc75fe494f1c62ba..8eb697db82d03606839e0002c5232513cfb80477 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * OnKey device driver for DA9063
+ * OnKey device driver for DA9063 and DA9062 PMICs
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/mfd/da9063/core.h>
 #include <linux/mfd/da9063/pdata.h>
 #include <linux/mfd/da9063/registers.h>
+#include <linux/mfd/da9062/core.h>
+#include <linux/mfd/da9062/registers.h>
+
+struct da906x_chip_config {
+       /* REGS */
+       int onkey_status;
+       int onkey_pwr_signalling;
+       int onkey_fault_log;
+       int onkey_shutdown;
+       /* MASKS */
+       int onkey_nonkey_mask;
+       int onkey_nonkey_lock_mask;
+       int onkey_key_reset_mask;
+       int onkey_shutdown_mask;
+       /* NAMES */
+       const char *name;
+};
 
 struct da9063_onkey {
-       struct da9063 *hw;
        struct delayed_work work;
        struct input_dev *input;
        struct device *dev;
+       struct regmap *regmap;
+       const struct da906x_chip_config *config;
+       char phys[32];
        bool key_power;
 };
 
+static const struct da906x_chip_config da9063_regs = {
+       /* REGS */
+       .onkey_status = DA9063_REG_STATUS_A,
+       .onkey_pwr_signalling = DA9063_REG_CONTROL_B,
+       .onkey_fault_log = DA9063_REG_FAULT_LOG,
+       .onkey_shutdown = DA9063_REG_CONTROL_F,
+       /* MASKS */
+       .onkey_nonkey_mask = DA9063_NONKEY,
+       .onkey_nonkey_lock_mask = DA9063_NONKEY_LOCK,
+       .onkey_key_reset_mask = DA9063_KEY_RESET,
+       .onkey_shutdown_mask = DA9063_SHUTDOWN,
+       /* NAMES */
+       .name = DA9063_DRVNAME_ONKEY,
+};
+
+static const struct da906x_chip_config da9062_regs = {
+       /* REGS */
+       .onkey_status = DA9062AA_STATUS_A,
+       .onkey_pwr_signalling = DA9062AA_CONTROL_B,
+       .onkey_fault_log = DA9062AA_FAULT_LOG,
+       .onkey_shutdown = DA9062AA_CONTROL_F,
+       /* MASKS */
+       .onkey_nonkey_mask = DA9062AA_NONKEY_MASK,
+       .onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK,
+       .onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK,
+       .onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK,
+       /* NAMES */
+       .name = "da9062-onkey",
+};
+
+static const struct of_device_id da9063_compatible_reg_id_table[] = {
+       { .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
+       { .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
+       { },
+};
+
 static void da9063_poll_on(struct work_struct *work)
 {
-       struct da9063_onkey *onkey = container_of(work, struct da9063_onkey,
-                                                 work.work);
+       struct da9063_onkey *onkey = container_of(work,
+                                               struct da9063_onkey,
+                                               work.work);
+       const struct da906x_chip_config *config = onkey->config;
        unsigned int val;
        int fault_log = 0;
        bool poll = true;
        int error;
 
        /* Poll to see when the pin is released */
-       error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
+       error = regmap_read(onkey->regmap,
+                           config->onkey_status,
+                           &val);
        if (error) {
                dev_err(onkey->dev,
                        "Failed to read ON status: %d\n", error);
                goto err_poll;
        }
 
-       if (!(val & DA9063_NONKEY)) {
-               error = regmap_update_bits(onkey->hw->regmap,
-                                          DA9063_REG_CONTROL_B,
-                                          DA9063_NONKEY_LOCK, 0);
+       if (!(val & config->onkey_nonkey_mask)) {
+               error = regmap_update_bits(onkey->regmap,
+                                          config->onkey_pwr_signalling,
+                                          config->onkey_nonkey_lock_mask,
+                                          0);
                if (error) {
                        dev_err(onkey->dev,
                                "Failed to reset the Key Delay %d\n", error);
@@ -70,15 +130,16 @@ static void da9063_poll_on(struct work_struct *work)
         * If the fault log KEY_RESET is detected, then clear it
         * and shut down the system.
         */
-       error = regmap_read(onkey->hw->regmap,
-                           DA9063_REG_FAULT_LOG, &fault_log);
+       error = regmap_read(onkey->regmap,
+                           config->onkey_fault_log,
+                           &fault_log);
        if (error) {
                dev_warn(&onkey->input->dev,
                         "Cannot read FAULT_LOG: %d\n", error);
-       } else if (fault_log & DA9063_KEY_RESET) {
-               error = regmap_write(onkey->hw->regmap,
-                                    DA9063_REG_FAULT_LOG,
-                                    DA9063_KEY_RESET);
+       } else if (fault_log & config->onkey_key_reset_mask) {
+               error = regmap_write(onkey->regmap,
+                                    config->onkey_fault_log,
+                                    config->onkey_key_reset_mask);
                if (error) {
                        dev_warn(&onkey->input->dev,
                                 "Cannot reset KEY_RESET fault log: %d\n",
@@ -88,10 +149,10 @@ static void da9063_poll_on(struct work_struct *work)
                         * and then send shutdown command
                         */
                        dev_dbg(&onkey->input->dev,
-                                "Sending SHUTDOWN to DA9063 ...\n");
-                       error = regmap_write(onkey->hw->regmap,
-                                            DA9063_REG_CONTROL_F,
-                                            DA9063_SHUTDOWN);
+                               "Sending SHUTDOWN to DA9063 ...\n");
+                       error = regmap_write(onkey->regmap,
+                                            config->onkey_shutdown,
+                                            config->onkey_shutdown_mask);
                        if (error)
                                dev_err(&onkey->input->dev,
                                        "Cannot SHUTDOWN DA9063: %d\n",
@@ -107,11 +168,14 @@ err_poll:
 static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
 {
        struct da9063_onkey *onkey = data;
+       const struct da906x_chip_config *config = onkey->config;
        unsigned int val;
        int error;
 
-       error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
-       if (onkey->key_power && !error && (val & DA9063_NONKEY)) {
+       error = regmap_read(onkey->regmap,
+                           config->onkey_status,
+                           &val);
+       if (onkey->key_power && !error && (val & config->onkey_nonkey_mask)) {
                input_report_key(onkey->input, KEY_POWER, 1);
                input_sync(onkey->input);
                schedule_delayed_work(&onkey->work, 0);
@@ -139,9 +203,15 @@ static int da9063_onkey_probe(struct platform_device *pdev)
        struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
        struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
        struct da9063_onkey *onkey;
+       const struct of_device_id *match;
        int irq;
        int error;
 
+       match = of_match_node(da9063_compatible_reg_id_table,
+                             pdev->dev.of_node);
+       if (!match)
+               return -ENXIO;
+
        onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
                             GFP_KERNEL);
        if (!onkey) {
@@ -149,8 +219,14 @@ static int da9063_onkey_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       onkey->config = match->data;
        onkey->dev = &pdev->dev;
-       onkey->hw = da9063;
+
+       onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!onkey->regmap) {
+               dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+               return -ENXIO;
+       }
 
        if (pdata)
                onkey->key_power = pdata->key_power;
@@ -165,8 +241,10 @@ static int da9063_onkey_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       onkey->input->name = DA9063_DRVNAME_ONKEY;
-       onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0";
+       onkey->input->name = onkey->config->name;
+       snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
+                onkey->config->name);
+       onkey->input->phys = onkey->phys;
        onkey->input->dev.parent = &pdev->dev;
 
        if (onkey->key_power)
@@ -216,11 +294,12 @@ static struct platform_driver da9063_onkey_driver = {
        .probe  = da9063_onkey_probe,
        .driver = {
                .name   = DA9063_DRVNAME_ONKEY,
+               .of_match_table = da9063_compatible_reg_id_table,
        },
 };
 module_platform_driver(da9063_onkey_driver);
 
 MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
index 45e0e3e55de28dfdbdfb347ebdba74ca2e698544..1c8c56efc995d3cfa0dc5392934beeeb2150734e 100644 (file)
@@ -198,7 +198,7 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
 
 
 /* Read the i8042 real-time clock */
-static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
+static inline int hp_sdc_rtc_read_rt(struct timespec64 *res) {
        int64_t raw;
        uint32_t tenms; 
        unsigned int days;
@@ -209,15 +209,15 @@ static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
        tenms = (uint32_t)raw & 0xffffff;
        days  = (unsigned int)(raw >> 24) & 0xffff;
 
-       res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
-       res->tv_sec =  (time_t)(tenms / 100) + days * 86400;
+       res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
+       res->tv_sec =  (tenms / 100) + (time64_t)days * 86400;
 
        return 0;
 }
 
 
 /* Read the i8042 fast handshake timer */
-static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
+static inline int hp_sdc_rtc_read_fhs(struct timespec64 *res) {
        int64_t raw;
        unsigned int tenms;
 
@@ -226,15 +226,15 @@ static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
 
        tenms = (unsigned int)raw & 0xffff;
 
-       res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
-       res->tv_sec  = (time_t)(tenms / 100);
+       res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
+       res->tv_sec  = (time64_t)(tenms / 100);
 
        return 0;
 }
 
 
 /* Read the i8042 match timer (a.k.a. alarm) */
-static inline int hp_sdc_rtc_read_mt(struct timeval *res) {
+static inline int hp_sdc_rtc_read_mt(struct timespec64 *res) {
        int64_t raw;    
        uint32_t tenms; 
 
@@ -243,15 +243,15 @@ static inline int hp_sdc_rtc_read_mt(struct timeval *res) {
 
        tenms = (uint32_t)raw & 0xffffff;
 
-       res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
-       res->tv_sec  = (time_t)(tenms / 100);
+       res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
+       res->tv_sec  = (time64_t)(tenms / 100);
 
        return 0;
 }
 
 
 /* Read the i8042 delay timer */
-static inline int hp_sdc_rtc_read_dt(struct timeval *res) {
+static inline int hp_sdc_rtc_read_dt(struct timespec64 *res) {
        int64_t raw;
        uint32_t tenms;
 
@@ -260,15 +260,15 @@ static inline int hp_sdc_rtc_read_dt(struct timeval *res) {
 
        tenms = (uint32_t)raw & 0xffffff;
 
-       res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
-       res->tv_sec  = (time_t)(tenms / 100);
+       res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
+       res->tv_sec  = (time64_t)(tenms / 100);
 
        return 0;
 }
 
 
 /* Read the i8042 cycle timer (a.k.a. periodic) */
-static inline int hp_sdc_rtc_read_ct(struct timeval *res) {
+static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) {
        int64_t raw;
        uint32_t tenms;
 
@@ -277,8 +277,8 @@ static inline int hp_sdc_rtc_read_ct(struct timeval *res) {
 
        tenms = (uint32_t)raw & 0xffffff;
 
-       res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
-       res->tv_sec  = (time_t)(tenms / 100);
+       res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
+       res->tv_sec  = (time64_t)(tenms / 100);
 
        return 0;
 }
@@ -433,7 +433,7 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v)
 #define YN(bit) ("no")
 #define NY(bit) ("yes")
         struct rtc_time tm;
-       struct timeval tv;
+       struct timespec64 tv;
 
        memset(&tm, 0, sizeof(struct rtc_time));
 
@@ -452,36 +452,36 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v)
        if (hp_sdc_rtc_read_rt(&tv)) {
                seq_puts(m, "i8042 rtc\t: READ FAILED!\n");
        } else {
-               seq_printf(m, "i8042 rtc\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, (int)tv.tv_usec/1000);
+               seq_printf(m, "i8042 rtc\t: %lld.%02ld seconds\n",
+                            (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
        }
 
        if (hp_sdc_rtc_read_fhs(&tv)) {
                seq_puts(m, "handshake\t: READ FAILED!\n");
        } else {
-               seq_printf(m, "handshake\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, (int)tv.tv_usec/1000);
+               seq_printf(m, "handshake\t: %lld.%02ld seconds\n",
+                            (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
        }
 
        if (hp_sdc_rtc_read_mt(&tv)) {
                seq_puts(m, "alarm\t\t: READ FAILED!\n");
        } else {
-               seq_printf(m, "alarm\t\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, (int)tv.tv_usec/1000);
+               seq_printf(m, "alarm\t\t: %lld.%02ld seconds\n",
+                            (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
        }
 
        if (hp_sdc_rtc_read_dt(&tv)) {
                seq_puts(m, "delay\t\t: READ FAILED!\n");
        } else {
-               seq_printf(m, "delay\t\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, (int)tv.tv_usec/1000);
+               seq_printf(m, "delay\t\t: %lld.%02ld seconds\n",
+                            (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
        }
 
        if (hp_sdc_rtc_read_ct(&tv)) {
                seq_puts(m, "periodic\t: READ FAILED!\n");
        } else {
-               seq_printf(m, "periodic\t: %ld.%02d seconds\n", 
-                            tv.tv_sec, (int)tv.tv_usec/1000);
+               seq_printf(m, "periodic\t: %lld.%02ld seconds\n",
+                            (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
        }
 
         seq_printf(m,
index e058d711256a203c97f8018824cba877fbdc0f05..efaffcc57e36cb58050a009830b5953bd08cb744 100644 (file)
@@ -635,7 +635,6 @@ static int __maybe_unused kxtj9_resume(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct kxtj9_data *tj9 = i2c_get_clientdata(client);
        struct input_dev *input_dev = tj9->input_dev;
-       int retval = 0;
 
        mutex_lock(&input_dev->mutex);
 
@@ -643,7 +642,7 @@ static int __maybe_unused kxtj9_resume(struct device *dev)
                kxtj9_enable(tj9);
 
        mutex_unlock(&input_dev->mutex);
-       return retval;
+       return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
index f27f81ee84edef53a4ed90ff150a7d096a43b2f7..8aee7198643001eb9252877b327569e4111744af 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
+#include <linux/pm.h>
 
 #define DRV_NAME "rotary-encoder"
 
@@ -142,6 +143,55 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       unsigned char sum;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       /*
+        * We encode the previous and the current state using a byte.
+        * The previous state in the MSB nibble, the current state in the LSB
+        * nibble. Then use a table to decide the direction of the turn.
+        */
+       sum = (encoder->last_stable << 4) + state;
+       switch (sum) {
+       case 0x31:
+       case 0x10:
+       case 0x02:
+       case 0x23:
+               encoder->dir = 0; /* clockwise */
+               break;
+
+       case 0x13:
+       case 0x01:
+       case 0x20:
+       case 0x32:
+               encoder->dir = 1; /* counter-clockwise */
+               break;
+
+       default:
+               /*
+                * Ignore all other values. This covers the case when the
+                * state didn't change (a spurious interrupt) and the
+                * cases where the state changed by two steps, making it
+                * impossible to tell the direction.
+                *
+                * In either case, don't report any event and save the
+                * state for later.
+                */
+               goto out;
+       }
+
+       rotary_encoder_report_event(encoder);
+
+out:
+       encoder->last_stable = state;
+       return IRQ_HANDLED;
+}
+
 #ifdef CONFIG_OF
 static const struct of_device_id rotary_encoder_of_match[] = {
        { .compatible = "rotary-encoder", },
@@ -156,6 +206,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
        struct device_node *np = dev->of_node;
        struct rotary_encoder_platform_data *pdata;
        enum of_gpio_flags flags;
+       int error;
 
        if (!of_id || !np)
                return NULL;
@@ -174,12 +225,27 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
        pdata->gpio_b = of_get_gpio_flags(np, 1, &flags);
        pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW;
 
-       pdata->relative_axis = !!of_get_property(np,
-                                       "rotary-encoder,relative-axis", NULL);
-       pdata->rollover = !!of_get_property(np,
-                                       "rotary-encoder,rollover", NULL);
-       pdata->half_period = !!of_get_property(np,
-                                       "rotary-encoder,half-period", NULL);
+       pdata->relative_axis =
+               of_property_read_bool(np, "rotary-encoder,relative-axis");
+       pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover");
+
+       error = of_property_read_u32(np, "rotary-encoder,steps-per-period",
+                                    &pdata->steps_per_period);
+       if (error) {
+               /*
+                * The 'half-period' property has been deprecated, you must use
+                * 'steps-per-period' and set an appropriate value, but we still
+                * need to parse it to maintain compatibility.
+                */
+               if (of_property_read_bool(np, "rotary-encoder,half-period")) {
+                       pdata->steps_per_period = 2;
+               } else {
+                       /* Fallback to one step per period behavior */
+                       pdata->steps_per_period = 1;
+               }
+       }
+
+       pdata->wakeup_source = of_property_read_bool(np, "wakeup-source");
 
        return pdata;
 }
@@ -250,12 +316,23 @@ static int rotary_encoder_probe(struct platform_device *pdev)
        encoder->irq_a = gpio_to_irq(pdata->gpio_a);
        encoder->irq_b = gpio_to_irq(pdata->gpio_b);
 
-       /* request the IRQs */
-       if (pdata->half_period) {
+       switch (pdata->steps_per_period) {
+       case 4:
+               handler = &rotary_encoder_quarter_period_irq;
+               encoder->last_stable = rotary_encoder_get_state(pdata);
+               break;
+       case 2:
                handler = &rotary_encoder_half_period_irq;
                encoder->last_stable = rotary_encoder_get_state(pdata);
-       } else {
+               break;
+       case 1:
                handler = &rotary_encoder_irq;
+               break;
+       default:
+               dev_err(dev, "'%d' is not a valid steps-per-period value\n",
+                       pdata->steps_per_period);
+               err = -EINVAL;
+               goto exit_free_gpio_b;
        }
 
        err = request_irq(encoder->irq_a, handler,
@@ -280,6 +357,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_irq_b;
        }
 
+       device_init_wakeup(&pdev->dev, pdata->wakeup_source);
+
        platform_set_drvdata(pdev, encoder);
 
        return 0;
@@ -306,6 +385,8 @@ static int rotary_encoder_remove(struct platform_device *pdev)
        struct rotary_encoder *encoder = platform_get_drvdata(pdev);
        const struct rotary_encoder_platform_data *pdata = encoder->pdata;
 
+       device_init_wakeup(&pdev->dev, false);
+
        free_irq(encoder->irq_a, encoder);
        free_irq(encoder->irq_b, encoder);
        gpio_free(pdata->gpio_a);
@@ -320,11 +401,41 @@ static int rotary_encoder_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rotary_encoder_suspend(struct device *dev)
+{
+       struct rotary_encoder *encoder = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               enable_irq_wake(encoder->irq_a);
+               enable_irq_wake(encoder->irq_b);
+       }
+
+       return 0;
+}
+
+static int rotary_encoder_resume(struct device *dev)
+{
+       struct rotary_encoder *encoder = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               disable_irq_wake(encoder->irq_a);
+               disable_irq_wake(encoder->irq_b);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
+                rotary_encoder_suspend, rotary_encoder_resume);
+
 static struct platform_driver rotary_encoder_driver = {
        .probe          = rotary_encoder_probe,
        .remove         = rotary_encoder_remove,
        .driver         = {
                .name   = DRV_NAME,
+               .pm     = &rotary_encoder_pm_ops,
                .of_match_table = of_match_ptr(rotary_encoder_of_match),
        }
 };
index 23d0549539d43904299c51810730f5d34955d952..0a9ad2cfb55c7fb53e39ef84e366668f5c531094 100644 (file)
@@ -129,8 +129,14 @@ static int xenkbd_probe(struct xenbus_device *dev,
 
        if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0)
                abs = 0;
-       if (abs)
-               xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1");
+       if (abs) {
+               ret = xenbus_printf(XBT_NIL, dev->nodename,
+                                   "request-abs-pointer", "1");
+               if (ret) {
+                       pr_warning("xenkbd: can't request abs-pointer");
+                       abs = 0;
+               }
+       }
 
        /* keyboard */
        kbd = input_allocate_device();
index 200841b77edb85b22caf110f4693443957354915..c3d05b4d3118d908434eb594659a97e0b4703b05 100644 (file)
@@ -292,4 +292,18 @@ config SERIO_SUN4I_PS2
          To compile this driver as a module, choose M here: the
          module will be called sun4i-ps2.
 
+config USERIO
+       tristate "User space serio port driver support"
+       help
+         Say Y here if you want to support user level drivers for serio
+         subsystem accessible under char device 10:240 - /dev/userio. Using
+         this facility userspace programs can implement serio ports that
+         will be used by the standard in-kernel serio consumer drivers,
+         such as psmouse and atkbd.
+
+         To compile this driver as a module, choose M here: the module will be
+         called userio.
+
+         If you are unsure, say N.
+
 endif
index c600089b7a349f2c05a624d27b5bbaeb646c9c45..2374ef9b33d788cee5693bb52905aabcd965df61 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_SERIO_APBPS2)    += apbps2.o
 obj-$(CONFIG_SERIO_OLPC_APSP)  += olpc_apsp.o
 obj-$(CONFIG_HYPERV_KEYBOARD)  += hyperv-keyboard.o
 obj-$(CONFIG_SERIO_SUN4I_PS2)  += sun4i-ps2.o
+obj-$(CONFIG_USERIO)           += userio.o
index 1e8cd6f1fe9e875005af95b54787890f81116a5f..74bb17270255439c6354f983676fdac121410c01 100644 (file)
@@ -141,19 +141,15 @@ static void parkbd_interrupt(void *dev_id)
        parkbd_last = jiffies;
 }
 
-static int parkbd_getport(void)
+static int parkbd_getport(struct parport *pp)
 {
-       struct parport *pp;
+       struct pardev_cb parkbd_parport_cb;
 
-       pp = parport_find_number(parkbd_pp_no);
+       parkbd_parport_cb.irq_func = parkbd_interrupt;
+       parkbd_parport_cb.flags = PARPORT_FLAG_EXCL;
 
-       if (pp == NULL) {
-               printk(KERN_ERR "parkbd: no such parport\n");
-               return -ENODEV;
-       }
-
-       parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL);
-       parport_put_port(pp);
+       parkbd_dev = parport_register_dev_model(pp, "parkbd",
+                                               &parkbd_parport_cb, 0);
 
        if (!parkbd_dev)
                return -ENODEV;
@@ -183,19 +179,21 @@ static struct serio * __init parkbd_allocate_serio(void)
        return serio;
 }
 
-static int __init parkbd_init(void)
+static void parkbd_attach(struct parport *pp)
 {
-       int err;
+       if (pp->number != parkbd_pp_no) {
+               pr_debug("Not using parport%d.\n", pp->number);
+               return;
+       }
 
-       err = parkbd_getport();
-       if (err)
-               return err;
+       if (parkbd_getport(pp))
+               return;
 
        parkbd_port = parkbd_allocate_serio();
        if (!parkbd_port) {
                parport_release(parkbd_dev);
                parport_unregister_device(parkbd_dev);
-               return -ENOMEM;
+               return;
        }
 
        parkbd_writelines(3);
@@ -205,14 +203,35 @@ static int __init parkbd_init(void)
        printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
                         parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
 
-       return 0;
+       return;
 }
 
-static void __exit parkbd_exit(void)
+static void parkbd_detach(struct parport *port)
 {
+       if (!parkbd_port || port->number != parkbd_pp_no)
+               return;
+
        parport_release(parkbd_dev);
        serio_unregister_port(parkbd_port);
        parport_unregister_device(parkbd_dev);
+       parkbd_port = NULL;
+}
+
+static struct parport_driver parkbd_parport_driver = {
+       .name = "parkbd",
+       .match_port = parkbd_attach,
+       .detach = parkbd_detach,
+       .devmodel = true,
+};
+
+static int __init parkbd_init(void)
+{
+       return parport_register_driver(&parkbd_parport_driver);
+}
+
+static void __exit parkbd_exit(void)
+{
+       parport_unregister_driver(&parkbd_parport_driver);
 }
 
 module_init(parkbd_init);
diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c
new file mode 100644 (file)
index 0000000..df1fd41
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * userio kernel serio device emulation module
+ * Copyright (C) 2015 Red Hat
+ * Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; 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 Lesser
+ * General Public License for more details.
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <uapi/linux/userio.h>
+
+#define USERIO_NAME            "userio"
+#define USERIO_BUFSIZE         16
+
+static struct miscdevice userio_misc;
+
+struct userio_device {
+       struct serio *serio;
+       struct mutex mutex;
+
+       bool running;
+
+       u8 head;
+       u8 tail;
+
+       spinlock_t buf_lock;
+       unsigned char buf[USERIO_BUFSIZE];
+
+       wait_queue_head_t waitq;
+};
+
+/**
+ * userio_device_write - Write data from serio to a userio device in userspace
+ * @id: The serio port for the userio device
+ * @val: The data to write to the device
+ */
+static int userio_device_write(struct serio *id, unsigned char val)
+{
+       struct userio_device *userio = id->port_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&userio->buf_lock, flags);
+
+       userio->buf[userio->head] = val;
+       userio->head = (userio->head + 1) % USERIO_BUFSIZE;
+
+       if (userio->head == userio->tail)
+               dev_warn(userio_misc.this_device,
+                        "Buffer overflowed, userio client isn't keeping up");
+
+       spin_unlock_irqrestore(&userio->buf_lock, flags);
+
+       wake_up_interruptible(&userio->waitq);
+
+       return 0;
+}
+
+static int userio_char_open(struct inode *inode, struct file *file)
+{
+       struct userio_device *userio;
+
+       userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL);
+       if (!userio)
+               return -ENOMEM;
+
+       mutex_init(&userio->mutex);
+       spin_lock_init(&userio->buf_lock);
+       init_waitqueue_head(&userio->waitq);
+
+       userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!userio->serio) {
+               kfree(userio);
+               return -ENOMEM;
+       }
+
+       userio->serio->write = userio_device_write;
+       userio->serio->port_data = userio;
+
+       file->private_data = userio;
+
+       return 0;
+}
+
+static int userio_char_release(struct inode *inode, struct file *file)
+{
+       struct userio_device *userio = file->private_data;
+
+       if (userio->running) {
+               /*
+                * Don't free the serio port here, serio_unregister_port()
+                * does it for us.
+                */
+               serio_unregister_port(userio->serio);
+       } else {
+               kfree(userio->serio);
+       }
+
+       kfree(userio);
+
+       return 0;
+}
+
+static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
+                               size_t count, loff_t *ppos)
+{
+       struct userio_device *userio = file->private_data;
+       int error;
+       size_t nonwrap_len, copylen;
+       unsigned char buf[USERIO_BUFSIZE];
+       unsigned long flags;
+
+       /*
+        * By the time we get here, the data that was waiting might have
+        * been taken by another thread. Grab the buffer lock and check if
+        * there's still any data waiting, otherwise repeat this process
+        * until we have data (unless the file descriptor is non-blocking
+        * of course).
+        */
+       for (;;) {
+               spin_lock_irqsave(&userio->buf_lock, flags);
+
+               nonwrap_len = CIRC_CNT_TO_END(userio->head,
+                                             userio->tail,
+                                             USERIO_BUFSIZE);
+               copylen = min(nonwrap_len, count);
+               if (copylen) {
+                       memcpy(buf, &userio->buf[userio->tail], copylen);
+                       userio->tail = (userio->tail + copylen) %
+                                                       USERIO_BUFSIZE;
+               }
+
+               spin_unlock_irqrestore(&userio->buf_lock, flags);
+
+               if (nonwrap_len)
+                       break;
+
+               /* buffer was/is empty */
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               /*
+                * count == 0 is special - no IO is done but we check
+                * for error conditions (see above).
+                */
+               if (count == 0)
+                       return 0;
+
+               error = wait_event_interruptible(userio->waitq,
+                                                userio->head != userio->tail);
+               if (error)
+                       return error;
+       }
+
+       if (copylen)
+               if (copy_to_user(user_buffer, buf, copylen))
+                       return -EFAULT;
+
+       return copylen;
+}
+
+static ssize_t userio_char_write(struct file *file, const char __user *buffer,
+                                size_t count, loff_t *ppos)
+{
+       struct userio_device *userio = file->private_data;
+       struct userio_cmd cmd;
+       int error;
+
+       if (count != sizeof(cmd)) {
+               dev_warn(userio_misc.this_device, "Invalid payload size\n");
+               return -EINVAL;
+       }
+
+       if (copy_from_user(&cmd, buffer, sizeof(cmd)))
+               return -EFAULT;
+
+       error = mutex_lock_interruptible(&userio->mutex);
+       if (error)
+               return error;
+
+       switch (cmd.type) {
+       case USERIO_CMD_REGISTER:
+               if (!userio->serio->id.type) {
+                       dev_warn(userio_misc.this_device,
+                                "No port type given on /dev/userio\n");
+
+                       error = -EINVAL;
+                       goto out;
+               }
+
+               if (userio->running) {
+                       dev_warn(userio_misc.this_device,
+                                "Begin command sent, but we're already running\n");
+                       error = -EBUSY;
+                       goto out;
+               }
+
+               userio->running = true;
+               serio_register_port(userio->serio);
+               break;
+
+       case USERIO_CMD_SET_PORT_TYPE:
+               if (userio->running) {
+                       dev_warn(userio_misc.this_device,
+                                "Can't change port type on an already running userio instance\n");
+                       error = -EBUSY;
+                       goto out;
+               }
+
+               userio->serio->id.type = cmd.data;
+               break;
+
+       case USERIO_CMD_SEND_INTERRUPT:
+               if (!userio->running) {
+                       dev_warn(userio_misc.this_device,
+                                "The device must be registered before sending interrupts\n");
+                       error = -ENODEV;
+                       goto out;
+               }
+
+               serio_interrupt(userio->serio, cmd.data, 0);
+               break;
+
+       default:
+               error = -EOPNOTSUPP;
+               goto out;
+       }
+
+out:
+       mutex_unlock(&userio->mutex);
+       return error ?: count;
+}
+
+static unsigned int userio_char_poll(struct file *file, poll_table *wait)
+{
+       struct userio_device *userio = file->private_data;
+
+       poll_wait(file, &userio->waitq, wait);
+
+       if (userio->head != userio->tail)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static const struct file_operations userio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = userio_char_open,
+       .release        = userio_char_release,
+       .read           = userio_char_read,
+       .write          = userio_char_write,
+       .poll           = userio_char_poll,
+       .llseek         = no_llseek,
+};
+
+static struct miscdevice userio_misc = {
+       .fops   = &userio_fops,
+       .minor  = USERIO_MINOR,
+       .name   = USERIO_NAME,
+};
+module_driver(userio_misc, misc_register, misc_deregister);
+
+MODULE_ALIAS_MISCDEV(USERIO_MINOR);
+MODULE_ALIAS("devname:" USERIO_NAME);
+
+MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("Virtual Serio Device Support");
+MODULE_LICENSE("GPL");
index deb14c12ae8b19a84c5ba8e0074f4bac43260ecc..80cc69897a4331105801ff3eca9339819727e3c8 100644 (file)
@@ -295,6 +295,19 @@ config TOUCHSCREEN_EGALAX
          To compile this driver as a module, choose M here: the
          module will be called egalax_ts.
 
+config TOUCHSCREEN_FT6236
+       tristate "FT6236 I2C touchscreen"
+       depends on I2C
+       depends on GPIOLIB || COMPILE_TEST
+       help
+         Say Y here to enable support for the I2C connected FT6x06 and
+         FT6x36 family of capacitive touchscreen drivers.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ft6236.
+
 config TOUCHSCREEN_FUJITSU
        tristate "Fujitsu serial touchscreen"
        select SERIO
@@ -1065,4 +1078,15 @@ config TOUCHSCREEN_COLIBRI_VF50
          To compile this driver as a module, choose M here: the
          module will be called colibri_vf50_ts.
 
+config TOUCHSCREEN_ROHM_BU21023
+       tristate "ROHM BU21023/24 Dual touch support resistive touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a touchscreen using ROHM BU21023/24.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bu21023_ts.
+
 endif
index 1b79cc09744af93b02ecabe958c24fc47bd189f3..17435c7e97e3bcbf421ce1135e9c64bec05f2c6a 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)                += eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELAN)         += elants_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)       += egalax_ts.o
+obj-$(CONFIG_TOUCHSCREEN_FT6236)       += ft6236.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)       += goodix.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)      += ili210x.o
@@ -87,3 +88,4 @@ obj-$(CONFIG_TOUCHSCREEN_SX8654)      += sx8654.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)     += tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ZFORCE)       += zforce_ts.o
 obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
+obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
index e431cf63a85d6600ea5b18d1b4008e8e5821e497..a61b2153ab8c20fb685d4af7595dba125df6023f 100644 (file)
@@ -529,10 +529,8 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
 
        ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias,
                                                      ts, ads7846_attr_groups);
-       if (IS_ERR(ts->hwmon))
-               return PTR_ERR(ts->hwmon);
 
-       return 0;
+       return PTR_ERR_OR_ZERO(ts->hwmon);
 }
 
 static void ads784x_hwmon_unregister(struct spi_device *spi,
index 38c06f754acd69abeb45ff3fbba766c9e01a09d6..6592fc5d48b489ee5cc6c7ea2fe797c7e19683b4 100644 (file)
@@ -399,13 +399,8 @@ static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
 static int auo_pixcir_input_open(struct input_dev *dev)
 {
        struct auo_pixcir_ts *ts = input_get_drvdata(dev);
-       int ret;
-
-       ret = auo_pixcir_start(ts);
-       if (ret)
-               return ret;
 
-       return 0;
+       return auo_pixcir_start(ts);
 }
 
 static void auo_pixcir_input_close(struct input_dev *dev)
index a9f95c7d3c0066cbd257b80755efdbe683340dbf..564e49002d5d61ae5632ac830a4bb0f3f05c32e2 100644 (file)
@@ -50,10 +50,7 @@ static int cyttsp4_i2c_probe(struct i2c_client *client,
        ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
                          CYTTSP4_I2C_DATA_SIZE);
 
-       if (IS_ERR(ts))
-               return PTR_ERR(ts);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(ts);
 }
 
 static int cyttsp4_i2c_remove(struct i2c_client *client)
index 48de1e8b3c93578cf4c1faf88c220c008a75569c..0b0f8c17f3f7e0f4df1e69144d693b46741f4025 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/module.h>
 #include <linux/ratelimit.h>
+#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
-#include <linux/input/edt-ft5x06.h>
-
-#define MAX_SUPPORT_POINTS             5
+#include <linux/of_device.h>
 
 #define WORK_REGISTER_THRESHOLD                0x00
 #define WORK_REGISTER_REPORT_RATE      0x08
@@ -91,9 +89,8 @@ struct edt_ft5x06_ts_data {
        u16 num_x;
        u16 num_y;
 
-       int reset_pin;
-       int irq_pin;
-       int wake_pin;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *wake_gpio;
 
 #if defined(CONFIG_DEBUG_FS)
        struct dentry *debug_dir;
@@ -107,6 +104,7 @@ struct edt_ft5x06_ts_data {
        int gain;
        int offset;
        int report_rate;
+       int max_support_points;
 
        char name[EDT_NAME_LEN];
 
@@ -114,6 +112,10 @@ struct edt_ft5x06_ts_data {
        enum edt_ver version;
 };
 
+struct edt_i2c_chip_data {
+       int  max_support_points;
+};
+
 static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
                                   u16 wr_len, u8 *wr_buf,
                                   u16 rd_len, u8 *rd_buf)
@@ -170,9 +172,9 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
        struct edt_ft5x06_ts_data *tsdata = dev_id;
        struct device *dev = &tsdata->client->dev;
        u8 cmd;
-       u8 rdbuf[29];
+       u8 rdbuf[63];
        int i, type, x, y, id;
-       int offset, tplen, datalen;
+       int offset, tplen, datalen, crclen;
        int error;
 
        switch (tsdata->version) {
@@ -180,14 +182,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
                cmd = 0xf9; /* tell the controller to send touch data */
                offset = 5; /* where the actual touch data starts */
                tplen = 4;  /* data comes in so called frames */
-               datalen = 26; /* how much bytes to listen for */
+               crclen = 1; /* length of the crc data */
                break;
 
        case M09:
-               cmd = 0x02;
-               offset = 1;
+               cmd = 0x0;
+               offset = 3;
                tplen = 6;
-               datalen = 29;
+               crclen = 0;
                break;
 
        default:
@@ -195,6 +197,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
        }
 
        memset(rdbuf, 0, sizeof(rdbuf));
+       datalen = tplen * tsdata->max_support_points + offset + crclen;
 
        error = edt_ft5x06_ts_readwrite(tsdata->client,
                                        sizeof(cmd), &cmd,
@@ -219,7 +222,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
                        goto out;
        }
 
-       for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
+       for (i = 0; i < tsdata->max_support_points; i++) {
                u8 *buf = &rdbuf[i * tplen + offset];
                bool down;
 
@@ -752,45 +755,6 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 
 #endif /* CONFIG_DEBUGFS */
 
-static int edt_ft5x06_ts_reset(struct i2c_client *client,
-                       struct edt_ft5x06_ts_data *tsdata)
-{
-       int error;
-
-       if (gpio_is_valid(tsdata->wake_pin)) {
-               error = devm_gpio_request_one(&client->dev,
-                                       tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
-                                       "edt-ft5x06 wake");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d as wake pin, error %d\n",
-                               tsdata->wake_pin, error);
-                       return error;
-               }
-
-               msleep(5);
-               gpio_set_value(tsdata->wake_pin, 1);
-       }
-       if (gpio_is_valid(tsdata->reset_pin)) {
-               /* this pulls reset down, enabling the low active reset */
-               error = devm_gpio_request_one(&client->dev,
-                                       tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
-                                       "edt-ft5x06 reset");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d as reset pin, error %d\n",
-                               tsdata->reset_pin, error);
-                       return error;
-               }
-
-               msleep(5);
-               gpio_set_value(tsdata->reset_pin, 1);
-               msleep(300);
-       }
-
-       return 0;
-}
-
 static int edt_ft5x06_ts_identify(struct i2c_client *client,
                                        struct edt_ft5x06_ts_data *tsdata,
                                        char *fw_version)
@@ -850,44 +814,24 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
        return 0;
 }
 
-#define EDT_ATTR_CHECKSET(name, reg) \
-do {                                                           \
-       if (pdata->name >= edt_ft5x06_attr_##name.limit_low &&          \
-           pdata->name <= edt_ft5x06_attr_##name.limit_high)           \
-               edt_ft5x06_register_write(tsdata, reg, pdata->name);    \
-} while (0)
-
-#define EDT_GET_PROP(name, reg) {                              \
-       u32 val;                                                \
-       if (of_property_read_u32(np, #name, &val) == 0)         \
-               edt_ft5x06_register_write(tsdata, reg, val);    \
-}
-
-static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
-                                       struct edt_ft5x06_ts_data *tsdata)
+static void edt_ft5x06_ts_get_defaults(struct device *dev,
+                                      struct edt_ft5x06_ts_data *tsdata)
 {
        struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+       u32 val;
+       int error;
 
-       EDT_GET_PROP(threshold, reg_addr->reg_threshold);
-       EDT_GET_PROP(gain, reg_addr->reg_gain);
-       EDT_GET_PROP(offset, reg_addr->reg_offset);
-}
+       error = device_property_read_u32(dev, "threshold", &val);
+       if (!error)
+               reg_addr->reg_threshold = val;
 
-static void
-edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
-                          const struct edt_ft5x06_platform_data *pdata)
-{
-       struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
-
-       if (!pdata->use_parameters)
-               return;
+       error = device_property_read_u32(dev, "gain", &val);
+       if (!error)
+               reg_addr->reg_gain = val;
 
-       /* pick up defaults from the platform data */
-       EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
-       EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
-       EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
-       if (reg_addr->reg_report_rate != NO_REGISTER)
-               EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
+       error = device_property_read_u32(dev, "offset", &val);
+       if (!error)
+               reg_addr->reg_offset = val;
 }
 
 static void
@@ -931,37 +875,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
        }
 }
 
-#ifdef CONFIG_OF
-static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
-                               struct edt_ft5x06_ts_data *tsdata)
-{
-       struct device_node *np = dev->of_node;
-
-       /*
-        * irq_pin is not needed for DT setup.
-        * irq is associated via 'interrupts' property in DT
-        */
-       tsdata->irq_pin = -EINVAL;
-       tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
-       tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
-
-       return 0;
-}
-#else
-static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
-                                       struct edt_ft5x06_ts_data *tsdata)
-{
-       return -ENODEV;
-}
-#endif
-
 static int edt_ft5x06_ts_probe(struct i2c_client *client,
                                         const struct i2c_device_id *id)
 {
-       const struct edt_ft5x06_platform_data *pdata =
-                                               dev_get_platdata(&client->dev);
+       const struct edt_i2c_chip_data *chip_data;
        struct edt_ft5x06_ts_data *tsdata;
        struct input_dev *input;
+       unsigned long irq_flags;
        int error;
        char fw_version[EDT_NAME_LEN];
 
@@ -973,32 +893,43 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
-       if (!pdata) {
-               error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
-               if (error) {
-                       dev_err(&client->dev,
-                               "DT probe failed and no platform data present\n");
-                       return error;
-               }
-       } else {
-               tsdata->reset_pin = pdata->reset_pin;
-               tsdata->irq_pin = pdata->irq_pin;
-               tsdata->wake_pin = -EINVAL;
+       chip_data = of_device_get_match_data(&client->dev);
+       if (!chip_data)
+               chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
+       if (!chip_data || !chip_data->max_support_points) {
+               dev_err(&client->dev, "invalid or missing chip data\n");
+               return -EINVAL;
        }
 
-       error = edt_ft5x06_ts_reset(client, tsdata);
-       if (error)
+       tsdata->max_support_points = chip_data->max_support_points;
+
+       tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
+                                                    "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(tsdata->reset_gpio)) {
+               error = PTR_ERR(tsdata->reset_gpio);
+               dev_err(&client->dev,
+                       "Failed to request GPIO reset pin, error %d\n", error);
+               return error;
+       }
+
+       tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev,
+                                                   "wake", GPIOD_OUT_LOW);
+       if (IS_ERR(tsdata->wake_gpio)) {
+               error = PTR_ERR(tsdata->wake_gpio);
+               dev_err(&client->dev,
+                       "Failed to request GPIO wake pin, error %d\n", error);
                return error;
+       }
 
-       if (gpio_is_valid(tsdata->irq_pin)) {
-               error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
-                                       GPIOF_IN, "edt-ft5x06 irq");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d, error %d\n",
-                               tsdata->irq_pin, error);
-                       return error;
-               }
+       if (tsdata->wake_gpio) {
+               usleep_range(5000, 6000);
+               gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
+       }
+
+       if (tsdata->reset_gpio) {
+               usleep_range(5000, 6000);
+               gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
+               msleep(300);
        }
 
        input = devm_input_allocate_device(&client->dev);
@@ -1019,12 +950,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        }
 
        edt_ft5x06_ts_set_regs(tsdata);
-
-       if (!pdata)
-               edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
-       else
-               edt_ft5x06_ts_get_defaults(tsdata, pdata);
-
+       edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
        edt_ft5x06_ts_get_parameters(tsdata);
 
        dev_dbg(&client->dev,
@@ -1040,10 +966,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        input_set_abs_params(input, ABS_MT_POSITION_Y,
                             0, tsdata->num_y * 64 - 1, 0, 0);
 
-       if (!pdata)
-               touchscreen_parse_properties(input, true);
+       touchscreen_parse_properties(input, true);
 
-       error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT);
+       error = input_mt_init_slots(input, tsdata->max_support_points,
+                               INPUT_MT_DIRECT);
        if (error) {
                dev_err(&client->dev, "Unable to init MT slots.\n");
                return error;
@@ -1052,9 +978,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        input_set_drvdata(input, tsdata);
        i2c_set_clientdata(client, tsdata);
 
-       error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
-                                       edt_ft5x06_ts_isr,
-                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+       irq_flags = irq_get_trigger_type(client->irq);
+       if (irq_flags == IRQF_TRIGGER_NONE)
+               irq_flags = IRQF_TRIGGER_FALLING;
+       irq_flags |= IRQF_ONESHOT;
+
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, edt_ft5x06_ts_isr, irq_flags,
                                        client->name, tsdata);
        if (error) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
@@ -1074,7 +1004,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 
        dev_dbg(&client->dev,
                "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
-               client->irq, tsdata->wake_pin, tsdata->reset_pin);
+               client->irq,
+               tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1,
+               tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
 
        return 0;
 
@@ -1116,17 +1048,27 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
                         edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
 
+static const struct edt_i2c_chip_data edt_ft5x06_data = {
+       .max_support_points = 5,
+};
+
+static const struct edt_i2c_chip_data edt_ft5506_data = {
+       .max_support_points = 10,
+};
+
 static const struct i2c_device_id edt_ft5x06_ts_id[] = {
-       { "edt-ft5x06", 0, },
+       { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
+       { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id edt_ft5x06_of_match[] = {
-       { .compatible = "edt,edt-ft5206", },
-       { .compatible = "edt,edt-ft5306", },
-       { .compatible = "edt,edt-ft5406", },
+       { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c
new file mode 100644 (file)
index 0000000..d240d2e
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * FocalTech FT6236 TouchScreen driver.
+ *
+ * Copyright (c) 2010  Focal tech Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/property.h>
+
+#define FT6236_MAX_TOUCH_POINTS                2
+
+#define FT6236_REG_TH_GROUP            0x80
+#define FT6236_REG_PERIODACTIVE                0x88
+#define FT6236_REG_LIB_VER_H           0xa1
+#define FT6236_REG_LIB_VER_L           0xa2
+#define FT6236_REG_CIPHER              0xa3
+#define FT6236_REG_FIRMID              0xa6
+#define FT6236_REG_FOCALTECH_ID                0xa8
+#define FT6236_REG_RELEASE_CODE_ID     0xaf
+
+#define FT6236_EVENT_PRESS_DOWN                0
+#define FT6236_EVENT_LIFT_UP           1
+#define FT6236_EVENT_CONTACT           2
+#define FT6236_EVENT_NO_EVENT          3
+
+struct ft6236_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+       struct gpio_desc *reset_gpio;
+       u32 max_x;
+       u32 max_y;
+       bool invert_x;
+       bool invert_y;
+       bool swap_xy;
+};
+
+/*
+ * This struct is a touchpoint as stored in hardware.  Note that the id,
+ * as well as the event, are stored in the upper nybble of the hi byte.
+ */
+struct ft6236_touchpoint {
+       union {
+               u8 xhi;
+               u8 event;
+       };
+       u8 xlo;
+       union {
+               u8 yhi;
+               u8 id;
+       };
+       u8 ylo;
+       u8 weight;
+       u8 misc;
+} __packed;
+
+/* This packet represents the register map as read from offset 0 */
+struct ft6236_packet {
+       u8 dev_mode;
+       u8 gest_id;
+       u8 touches;
+       struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS];
+} __packed;
+
+static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data)
+{
+       int error;
+
+       error = i2c_smbus_read_i2c_block_data(client, reg, len, data);
+       if (error < 0)
+               return error;
+
+       if (error != len)
+               return -EIO;
+
+       return 0;
+}
+
+static irqreturn_t ft6236_interrupt(int irq, void *dev_id)
+{
+       struct ft6236_data *ft6236 = dev_id;
+       struct device *dev = &ft6236->client->dev;
+       struct input_dev *input = ft6236->input;
+       struct ft6236_packet buf;
+       u8 touches;
+       int i, error;
+
+       error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf);
+       if (error) {
+               dev_err(dev, "read touchdata failed %d\n", error);
+               return IRQ_HANDLED;
+       }
+
+       touches = buf.touches & 0xf;
+       if (touches > FT6236_MAX_TOUCH_POINTS) {
+               dev_dbg(dev,
+                       "%d touch points reported, only %d are supported\n",
+                       touches, FT6236_MAX_TOUCH_POINTS);
+               touches = FT6236_MAX_TOUCH_POINTS;
+       }
+
+       for (i = 0; i < touches; i++) {
+               struct ft6236_touchpoint *point = &buf.points[i];
+               u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo;
+               u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo;
+               u8 event = point->event >> 6;
+               u8 id = point->id >> 4;
+               bool act = (event == FT6236_EVENT_PRESS_DOWN ||
+                           event == FT6236_EVENT_CONTACT);
+
+               input_mt_slot(input, id);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, act);
+               if (!act)
+                       continue;
+
+               if (ft6236->invert_x)
+                       x = ft6236->max_x - x;
+
+               if (ft6236->invert_y)
+                       y = ft6236->max_y - y;
+
+               if (ft6236->swap_xy) {
+                       input_report_abs(input, ABS_MT_POSITION_X, y);
+                       input_report_abs(input, ABS_MT_POSITION_Y, x);
+               } else {
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+               }
+       }
+
+       input_mt_sync_frame(input);
+       input_sync(input);
+
+       return IRQ_HANDLED;
+}
+
+static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg)
+{
+       struct i2c_client *client = ft6236->client;
+       u8 val = 0;
+       int error;
+
+       error = ft6236_read(client, reg, 1, &val);
+       if (error)
+               dev_dbg(&client->dev,
+                       "error reading register 0x%02x: %d\n", reg, error);
+
+       return val;
+}
+
+static void ft6236_debug_info(struct ft6236_data *ft6236)
+{
+       struct device *dev = &ft6236->client->dev;
+
+       dev_dbg(dev, "Touch threshold is %d\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4);
+       dev_dbg(dev, "Report rate is %dHz\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10);
+       dev_dbg(dev, "Firmware library version 0x%02x%02x\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H),
+               ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L));
+       dev_dbg(dev, "Firmware version 0x%02x\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID));
+       dev_dbg(dev, "Chip vendor ID 0x%02x\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER));
+       dev_dbg(dev, "CTPM vendor ID 0x%02x\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID));
+       dev_dbg(dev, "Release code version 0x%02x\n",
+               ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID));
+}
+
+static void ft6236_reset(struct ft6236_data *ft6236)
+{
+       if (!ft6236->reset_gpio)
+               return;
+
+       gpiod_set_value_cansleep(ft6236->reset_gpio, 1);
+       usleep_range(5000, 20000);
+       gpiod_set_value_cansleep(ft6236->reset_gpio, 0);
+       msleep(300);
+}
+
+static int ft6236_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct ft6236_data *ft6236;
+       struct input_dev *input;
+       u32 fuzz_x = 0, fuzz_y = 0;
+       u8 val;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENXIO;
+
+       if (!client->irq) {
+               dev_err(dev, "irq is missing\n");
+               return -EINVAL;
+       }
+
+       ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL);
+       if (!ft6236)
+               return -ENOMEM;
+
+       ft6236->client = client;
+       ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(ft6236->reset_gpio)) {
+               error = PTR_ERR(ft6236->reset_gpio);
+               if (error != -EPROBE_DEFER)
+                       dev_err(dev, "error getting reset gpio: %d\n", error);
+               return error;
+       }
+
+       ft6236_reset(ft6236);
+
+       /* verify that the controller is present */
+       error = ft6236_read(client, 0x00, 1, &val);
+       if (error) {
+               dev_err(dev, "failed to read from controller: %d\n", error);
+               return error;
+       }
+
+       ft6236_debug_info(ft6236);
+
+       input = devm_input_allocate_device(dev);
+       if (!input)
+               return -ENOMEM;
+
+       ft6236->input = input;
+       input->name = client->name;
+       input->id.bustype = BUS_I2C;
+
+       if (device_property_read_u32(dev, "touchscreen-size-x",
+                                    &ft6236->max_x) ||
+           device_property_read_u32(dev, "touchscreen-size-y",
+                                    &ft6236->max_y)) {
+               dev_err(dev, "touchscreen-size-x and/or -y missing\n");
+               return -EINVAL;
+       }
+
+       device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x);
+       device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y);
+       ft6236->invert_x = device_property_read_bool(dev,
+                                                    "touchscreen-inverted-x");
+       ft6236->invert_y = device_property_read_bool(dev,
+                                                    "touchscreen-inverted-y");
+       ft6236->swap_xy = device_property_read_bool(dev,
+                                                   "touchscreen-swapped-x-y");
+
+       if (ft6236->swap_xy) {
+               input_set_abs_params(input, ABS_MT_POSITION_X, 0,
+                                    ft6236->max_y, fuzz_y, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
+                                    ft6236->max_x, fuzz_x, 0);
+       } else {
+               input_set_abs_params(input, ABS_MT_POSITION_X, 0,
+                                    ft6236->max_x, fuzz_x, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
+                                    ft6236->max_y, fuzz_y, 0);
+       }
+
+       error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS,
+                                   INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+       if (error)
+               return error;
+
+       error = devm_request_threaded_irq(dev, client->irq, NULL,
+                                         ft6236_interrupt, IRQF_ONESHOT,
+                                         client->name, ft6236);
+       if (error) {
+               dev_err(dev, "request irq %d failed: %d\n", client->irq, error);
+               return error;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(dev, "failed to register input device: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ft6236_of_match[] = {
+       { .compatible = "focaltech,ft6236", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ft6236_of_match);
+#endif
+
+static const struct i2c_device_id ft6236_id[] = {
+       { "ft6236", },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ft6236_id);
+
+static struct i2c_driver ft6236_driver = {
+       .driver = {
+               .name = "ft6236",
+               .of_match_table = of_match_ptr(ft6236_of_match),
+       },
+       .probe = ft6236_probe,
+       .id_table = ft6236_id,
+};
+module_i2c_driver(ft6236_driver);
+
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_AUTHOR("Noralf Trønnes <noralf@tronnes.org>");
+MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver");
+MODULE_LICENSE("GPL v2");
index 91621725bfb519b58cff540281822c635ed2948e..4b961ad9f0b51cb905e25c8f272b16378078d5c5 100644 (file)
@@ -377,8 +377,6 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev)
                                goto unlock;
                        }
                }
-
-               enable_irq_wake(client->irq);
        } else if (input->users) {
                ret = pixcir_stop(ts);
        }
@@ -399,7 +397,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev)
        mutex_lock(&input->mutex);
 
        if (device_may_wakeup(&client->dev)) {
-               disable_irq_wake(client->irq);
 
                if (!input->users) {
                        ret = pixcir_stop(ts);
@@ -564,14 +561,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
                return error;
 
        i2c_set_clientdata(client, tsdata);
-       device_init_wakeup(&client->dev, 1);
-
-       return 0;
-}
-
-static int pixcir_i2c_ts_remove(struct i2c_client *client)
-{
-       device_init_wakeup(&client->dev, 0);
 
        return 0;
 }
@@ -609,7 +598,6 @@ static struct i2c_driver pixcir_i2c_ts_driver = {
                .of_match_table = of_match_ptr(pixcir_of_match),
        },
        .probe          = pixcir_i2c_ts_probe,
-       .remove         = pixcir_i2c_ts_remove,
        .id_table       = pixcir_i2c_ts_id,
 };
 
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
new file mode 100644 (file)
index 0000000..ba6024f
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+ * ROHM BU21023/24 Dual touch support resistive touch screen driver
+ * Copyright (C) 2012 ROHM CO.,LTD.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#define BU21023_NAME                   "bu21023_ts"
+#define BU21023_FIRMWARE_NAME          "bu21023.bin"
+
+#define MAX_CONTACTS                   2
+
+#define AXIS_ADJUST                    4
+#define AXIS_OFFSET                    8
+
+#define FIRMWARE_BLOCK_SIZE            32U
+#define FIRMWARE_RETRY_MAX             4
+
+#define SAMPLING_DELAY                 12      /* msec */
+
+#define CALIBRATION_RETRY_MAX          6
+
+#define ROHM_TS_ABS_X_MIN              40
+#define ROHM_TS_ABS_X_MAX              990
+#define ROHM_TS_ABS_Y_MIN              160
+#define ROHM_TS_ABS_Y_MAX              920
+#define ROHM_TS_DISPLACEMENT_MAX       0       /* zero for infinite */
+
+/*
+ * BU21023GUL/BU21023MUV/BU21024FV-M registers map
+ */
+#define VADOUT_YP_H            0x00
+#define VADOUT_YP_L            0x01
+#define VADOUT_XP_H            0x02
+#define VADOUT_XP_L            0x03
+#define VADOUT_YN_H            0x04
+#define VADOUT_YN_L            0x05
+#define VADOUT_XN_H            0x06
+#define VADOUT_XN_L            0x07
+
+#define PRM1_X_H               0x08
+#define PRM1_X_L               0x09
+#define PRM1_Y_H               0x0a
+#define PRM1_Y_L               0x0b
+#define PRM2_X_H               0x0c
+#define PRM2_X_L               0x0d
+#define PRM2_Y_H               0x0e
+#define PRM2_Y_L               0x0f
+
+#define MLT_PRM_MONI_X         0x10
+#define MLT_PRM_MONI_Y         0x11
+
+#define DEBUG_MONI_1           0x12
+#define DEBUG_MONI_2           0x13
+
+#define VADOUT_ZX_H            0x14
+#define VADOUT_ZX_L            0x15
+#define VADOUT_ZY_H            0x16
+#define VADOUT_ZY_L            0x17
+
+#define Z_PARAM_H              0x18
+#define Z_PARAM_L              0x19
+
+/*
+ * Value for VADOUT_*_L
+ */
+#define VADOUT_L_MASK          0x01
+
+/*
+ * Value for PRM*_*_L
+ */
+#define PRM_L_MASK             0x01
+
+#define POS_X1_H               0x20
+#define POS_X1_L               0x21
+#define POS_Y1_H               0x22
+#define POS_Y1_L               0x23
+#define POS_X2_H               0x24
+#define POS_X2_L               0x25
+#define POS_Y2_H               0x26
+#define POS_Y2_L               0x27
+
+/*
+ * Value for POS_*_L
+ */
+#define POS_L_MASK             0x01
+
+#define TOUCH                  0x28
+#define TOUCH_DETECT           0x01
+
+#define TOUCH_GESTURE          0x29
+#define SINGLE_TOUCH           0x01
+#define DUAL_TOUCH             0x03
+#define TOUCH_MASK             0x03
+#define CALIBRATION_REQUEST    0x04
+#define CALIBRATION_STATUS     0x08
+#define CALIBRATION_MASK       0x0c
+#define GESTURE_SPREAD         0x10
+#define GESTURE_PINCH          0x20
+#define GESTURE_ROTATE_R       0x40
+#define GESTURE_ROTATE_L       0x80
+
+#define INT_STATUS             0x2a
+#define INT_MASK               0x3d
+#define INT_CLEAR              0x3e
+
+/*
+ * Values for INT_*
+ */
+#define COORD_UPDATE           0x01
+#define CALIBRATION_DONE       0x02
+#define SLEEP_IN               0x04
+#define SLEEP_OUT              0x08
+#define PROGRAM_LOAD_DONE      0x10
+#define ERROR                  0x80
+#define INT_ALL                        0x9f
+
+#define ERR_STATUS             0x2b
+#define ERR_MASK               0x3f
+
+/*
+ * Values for ERR_*
+ */
+#define ADC_TIMEOUT            0x01
+#define CPU_TIMEOUT            0x02
+#define CALIBRATION_ERR                0x04
+#define PROGRAM_LOAD_ERR       0x10
+
+#define COMMON_SETUP1                  0x30
+#define PROGRAM_LOAD_HOST              0x02
+#define PROGRAM_LOAD_EEPROM            0x03
+#define CENSOR_4PORT                   0x04
+#define CENSOR_8PORT                   0x00    /* Not supported by BU21023 */
+#define CALIBRATION_TYPE_DEFAULT       0x08
+#define CALIBRATION_TYPE_SPECIAL       0x00
+#define INT_ACTIVE_HIGH                        0x10
+#define INT_ACTIVE_LOW                 0x00
+#define AUTO_CALIBRATION               0x40
+#define MANUAL_CALIBRATION             0x00
+#define COMMON_SETUP1_DEFAULT          0x4e
+
+#define COMMON_SETUP2          0x31
+#define MAF_NONE               0x00
+#define MAF_1SAMPLE            0x01
+#define MAF_3SAMPLES           0x02
+#define MAF_5SAMPLES           0x03
+#define INV_Y                  0x04
+#define INV_X                  0x08
+#define SWAP_XY                        0x10
+
+#define COMMON_SETUP3          0x32
+#define EN_SLEEP               0x01
+#define EN_MULTI               0x02
+#define EN_GESTURE             0x04
+#define EN_INTVL               0x08
+#define SEL_STEP               0x10
+#define SEL_MULTI              0x20
+#define SEL_TBL_DEFAULT                0x40
+
+#define INTERVAL_TIME          0x33
+#define INTERVAL_TIME_DEFAULT  0x10
+
+#define STEP_X                 0x34
+#define STEP_X_DEFAULT         0x41
+
+#define STEP_Y                 0x35
+#define STEP_Y_DEFAULT         0x8d
+
+#define OFFSET_X               0x38
+#define OFFSET_X_DEFAULT       0x0c
+
+#define OFFSET_Y               0x39
+#define OFFSET_Y_DEFAULT       0x0c
+
+#define THRESHOLD_TOUCH                0x3a
+#define THRESHOLD_TOUCH_DEFAULT        0xa0
+
+#define THRESHOLD_GESTURE              0x3b
+#define THRESHOLD_GESTURE_DEFAULT      0x17
+
+#define SYSTEM                 0x40
+#define ANALOG_POWER_ON                0x01
+#define ANALOG_POWER_OFF       0x00
+#define CPU_POWER_ON           0x02
+#define CPU_POWER_OFF          0x00
+
+#define FORCE_CALIBRATION      0x42
+#define FORCE_CALIBRATION_ON   0x01
+#define FORCE_CALIBRATION_OFF  0x00
+
+#define CPU_FREQ               0x50    /* 10 / (reg + 1) MHz */
+#define CPU_FREQ_10MHZ         0x00
+#define CPU_FREQ_5MHZ          0x01
+#define CPU_FREQ_1MHZ          0x09
+
+#define EEPROM_ADDR            0x51
+
+#define CALIBRATION_ADJUST             0x52
+#define CALIBRATION_ADJUST_DEFAULT     0x00
+
+#define THRESHOLD_SLEEP_IN     0x53
+
+#define EVR_XY                 0x56
+#define EVR_XY_DEFAULT         0x10
+
+#define PRM_SWOFF_TIME         0x57
+#define PRM_SWOFF_TIME_DEFAULT 0x04
+
+#define PROGRAM_VERSION                0x5f
+
+#define ADC_CTRL               0x60
+#define ADC_DIV_MASK           0x1f    /* The minimum value is 4 */
+#define ADC_DIV_DEFAULT                0x08
+
+#define ADC_WAIT               0x61
+#define ADC_WAIT_DEFAULT       0x0a
+
+#define SWCONT                 0x62
+#define SWCONT_DEFAULT         0x0f
+
+#define EVR_X                  0x63
+#define EVR_X_DEFAULT          0x86
+
+#define EVR_Y                  0x64
+#define EVR_Y_DEFAULT          0x64
+
+#define TEST1                  0x65
+#define DUALTOUCH_STABILIZE_ON 0x01
+#define DUALTOUCH_STABILIZE_OFF        0x00
+#define DUALTOUCH_REG_ON       0x20
+#define DUALTOUCH_REG_OFF      0x00
+
+#define CALIBRATION_REG1               0x68
+#define CALIBRATION_REG1_DEFAULT       0xd9
+
+#define CALIBRATION_REG2               0x69
+#define CALIBRATION_REG2_DEFAULT       0x36
+
+#define CALIBRATION_REG3               0x6a
+#define CALIBRATION_REG3_DEFAULT       0x32
+
+#define EX_ADDR_H              0x70
+#define EX_ADDR_L              0x71
+#define EX_WDAT                        0x72
+#define EX_RDAT                        0x73
+#define EX_CHK_SUM1            0x74
+#define EX_CHK_SUM2            0x75
+#define EX_CHK_SUM3            0x76
+
+struct rohm_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+
+       bool initialized;
+
+       unsigned int contact_count[MAX_CONTACTS + 1];
+       int finger_count;
+
+       u8 setup2;
+};
+
+/*
+ * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24
+ * @client: Handle to ROHM BU21023/24
+ * @start: Where to start read address from ROHM BU21023/24
+ * @buf: Where to store read data from ROHM BU21023/24
+ * @len: How many bytes to read
+ *
+ * Returns negative errno, else zero on success.
+ *
+ * Note
+ * In BU21023/24 burst read, stop condition is needed after "address write".
+ * Therefore, transmission is performed in 2 steps.
+ */
+static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf,
+                              size_t len)
+{
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg[2];
+       int i, ret = 0;
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 1;
+       msg[0].buf = &start;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = len;
+       msg[1].buf = buf;
+
+       i2c_lock_adapter(adap);
+
+       for (i = 0; i < 2; i++) {
+               if (__i2c_transfer(adap, &msg[i], 1) < 0) {
+                       ret = -EIO;
+                       break;
+               }
+       }
+
+       i2c_unlock_adapter(adap);
+
+       return ret;
+}
+
+static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
+{
+       struct i2c_client *client = ts->client;
+       struct device *dev = &client->dev;
+       u8 buf[33];     /* for PRM1_X_H(0x08)-TOUCH(0x28) */
+
+       int retry;
+       bool success = false;
+       bool first_time = true;
+       bool calibration_done;
+
+       u8 reg1, reg2, reg3;
+       s32 reg1_orig, reg2_orig, reg3_orig;
+       s32 val;
+
+       int calib_x = 0, calib_y = 0;
+       int reg_x, reg_y;
+       int err_x, err_y;
+
+       int error, error2;
+       int i;
+
+       reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1);
+       if (reg1_orig < 0)
+               return reg1_orig;
+
+       reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2);
+       if (reg2_orig < 0)
+               return reg2_orig;
+
+       reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3);
+       if (reg3_orig < 0)
+               return reg3_orig;
+
+       error = i2c_smbus_write_byte_data(client, INT_MASK,
+                                         COORD_UPDATE | SLEEP_IN | SLEEP_OUT |
+                                         PROGRAM_LOAD_DONE);
+       if (error)
+               goto out;
+
+       error = i2c_smbus_write_byte_data(client, TEST1,
+                                         DUALTOUCH_STABILIZE_ON);
+       if (error)
+               goto out;
+
+       for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) {
+               /* wait 2 sampling for update */
+               mdelay(2 * SAMPLING_DELAY);
+
+#define READ_CALIB_BUF(reg)    buf[((reg) - PRM1_X_H)]
+
+               error = rohm_i2c_burst_read(client, PRM1_X_H, buf, sizeof(buf));
+               if (error)
+                       goto out;
+
+               if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT)
+                       continue;
+
+               if (first_time) {
+                       /* generate calibration parameter */
+                       calib_x = ((int)READ_CALIB_BUF(PRM1_X_H) << 2 |
+                               READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET;
+                       calib_y = ((int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
+                               READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET;
+
+                       error = i2c_smbus_write_byte_data(client, TEST1,
+                               DUALTOUCH_STABILIZE_ON | DUALTOUCH_REG_ON);
+                       if (error)
+                               goto out;
+
+                       first_time = false;
+               } else {
+                       /* generate adjustment parameter */
+                       err_x = (int)READ_CALIB_BUF(PRM1_X_H) << 2 |
+                               READ_CALIB_BUF(PRM1_X_L);
+                       err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
+                               READ_CALIB_BUF(PRM1_Y_L);
+
+                       /* X axis ajust */
+                       if (err_x <= 4)
+                               calib_x -= AXIS_ADJUST;
+                       else if (err_x >= 60)
+                               calib_x += AXIS_ADJUST;
+
+                       /* Y axis ajust */
+                       if (err_y <= 4)
+                               calib_y -= AXIS_ADJUST;
+                       else if (err_y >= 60)
+                               calib_y += AXIS_ADJUST;
+               }
+
+               /* generate calibration setting value */
+               reg_x = calib_x + ((calib_x & 0x200) << 1);
+               reg_y = calib_y + ((calib_y & 0x200) << 1);
+
+               /* convert for register format */
+               reg1 = reg_x >> 3;
+               reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7);
+               reg3 = reg_y >> 3;
+
+               error = i2c_smbus_write_byte_data(client,
+                                                 CALIBRATION_REG1, reg1);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client,
+                                                 CALIBRATION_REG2, reg2);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client,
+                                                 CALIBRATION_REG3, reg3);
+               if (error)
+                       goto out;
+
+               /*
+                * force calibration sequcence
+                */
+               error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+                                                 FORCE_CALIBRATION_OFF);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+                                                 FORCE_CALIBRATION_ON);
+               if (error)
+                       goto out;
+
+               /* clear all interrupts */
+               error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+               if (error)
+                       goto out;
+
+               /*
+                * Wait for the status change of calibration, max 10 sampling
+                */
+               calibration_done = false;
+
+               for (i = 0; i < 10; i++) {
+                       mdelay(SAMPLING_DELAY);
+
+                       val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE);
+                       if (!(val & CALIBRATION_MASK)) {
+                               calibration_done = true;
+                               break;
+                       } else if (val < 0) {
+                               error = val;
+                               goto out;
+                       }
+               }
+
+               if (calibration_done) {
+                       val = i2c_smbus_read_byte_data(client, INT_STATUS);
+                       if (val == CALIBRATION_DONE) {
+                               success = true;
+                               break;
+                       } else if (val < 0) {
+                               error = val;
+                               goto out;
+                       }
+               } else {
+                       dev_warn(dev, "calibration timeout\n");
+               }
+       }
+
+       if (!success) {
+               error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
+                                                 reg1_orig);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
+                                                 reg2_orig);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
+                                                 reg3_orig);
+               if (error)
+                       goto out;
+
+               /* calibration data enable */
+               error = i2c_smbus_write_byte_data(client, TEST1,
+                                                 DUALTOUCH_STABILIZE_ON |
+                                                 DUALTOUCH_REG_ON);
+               if (error)
+                       goto out;
+
+               /* wait 10 sampling */
+               mdelay(10 * SAMPLING_DELAY);
+
+               error = -EBUSY;
+       }
+
+out:
+       error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+       if (!error2)
+               /* Clear all interrupts */
+               error2 = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+       return error ? error : error2;
+}
+
+static const unsigned int untouch_threshold[3] = { 0, 1, 5 };
+static const unsigned int single_touch_threshold[3] = { 0, 0, 4 };
+static const unsigned int dual_touch_threshold[3] = { 10, 8, 0 };
+
+static irqreturn_t rohm_ts_soft_irq(int irq, void *dev_id)
+{
+       struct rohm_ts_data *ts = dev_id;
+       struct i2c_client *client = ts->client;
+       struct input_dev *input_dev = ts->input;
+       struct device *dev = &client->dev;
+
+       u8 buf[10];     /* for POS_X1_H(0x20)-TOUCH_GESTURE(0x29) */
+
+       struct input_mt_pos pos[MAX_CONTACTS];
+       int slots[MAX_CONTACTS];
+       u8 touch_flags;
+       unsigned int threshold;
+       int finger_count = -1;
+       int prev_finger_count = ts->finger_count;
+       int count;
+       int error;
+       int i;
+
+       error = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+       if (error)
+               return IRQ_HANDLED;
+
+       /* Clear all interrupts */
+       error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+       if (error)
+               return IRQ_HANDLED;
+
+#define READ_POS_BUF(reg)      buf[((reg) - POS_X1_H)]
+
+       error = rohm_i2c_burst_read(client, POS_X1_H, buf, sizeof(buf));
+       if (error)
+               return IRQ_HANDLED;
+
+       touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK;
+       if (touch_flags) {
+               /* generate coordinates */
+               pos[0].x = ((s16)READ_POS_BUF(POS_X1_H) << 2) |
+                          READ_POS_BUF(POS_X1_L);
+               pos[0].y = ((s16)READ_POS_BUF(POS_Y1_H) << 2) |
+                          READ_POS_BUF(POS_Y1_L);
+               pos[1].x = ((s16)READ_POS_BUF(POS_X2_H) << 2) |
+                          READ_POS_BUF(POS_X2_L);
+               pos[1].y = ((s16)READ_POS_BUF(POS_Y2_H) << 2) |
+                          READ_POS_BUF(POS_Y2_L);
+       }
+
+       switch (touch_flags) {
+       case 0:
+               threshold = untouch_threshold[prev_finger_count];
+               if (++ts->contact_count[0] >= threshold)
+                       finger_count = 0;
+               break;
+
+       case SINGLE_TOUCH:
+               threshold = single_touch_threshold[prev_finger_count];
+               if (++ts->contact_count[1] >= threshold)
+                       finger_count = 1;
+
+               if (finger_count == 1) {
+                       if (pos[1].x != 0 && pos[1].y != 0) {
+                               pos[0].x = pos[1].x;
+                               pos[0].y = pos[1].y;
+                               pos[1].x = 0;
+                               pos[1].y = 0;
+                       }
+               }
+               break;
+
+       case DUAL_TOUCH:
+               threshold = dual_touch_threshold[prev_finger_count];
+               if (++ts->contact_count[2] >= threshold)
+                       finger_count = 2;
+               break;
+
+       default:
+               dev_dbg(dev,
+                       "Three or more touches are not supported\n");
+               return IRQ_HANDLED;
+       }
+
+       if (finger_count >= 0) {
+               if (prev_finger_count != finger_count) {
+                       count = ts->contact_count[finger_count];
+                       memset(ts->contact_count, 0, sizeof(ts->contact_count));
+                       ts->contact_count[finger_count] = count;
+               }
+
+               input_mt_assign_slots(input_dev, slots, pos,
+                                     finger_count, ROHM_TS_DISPLACEMENT_MAX);
+
+               for (i = 0; i < finger_count; i++) {
+                       input_mt_slot(input_dev, slots[i]);
+                       input_mt_report_slot_state(input_dev,
+                                                  MT_TOOL_FINGER, true);
+                       input_report_abs(input_dev,
+                                        ABS_MT_POSITION_X, pos[i].x);
+                       input_report_abs(input_dev,
+                                        ABS_MT_POSITION_Y, pos[i].y);
+               }
+
+               input_mt_sync_frame(input_dev);
+               input_mt_report_pointer_emulation(input_dev, true);
+               input_sync(input_dev);
+
+               ts->finger_count = finger_count;
+       }
+
+       if (READ_POS_BUF(TOUCH_GESTURE) & CALIBRATION_REQUEST) {
+               error = rohm_ts_manual_calibration(ts);
+               if (error)
+                       dev_warn(dev, "manual calibration failed: %d\n",
+                                error);
+       }
+
+       i2c_smbus_write_byte_data(client, INT_MASK,
+                                 CALIBRATION_DONE | SLEEP_OUT | SLEEP_IN |
+                                 PROGRAM_LOAD_DONE);
+
+       return IRQ_HANDLED;
+}
+
+static int rohm_ts_load_firmware(struct i2c_client *client,
+                                const char *firmware_name)
+{
+       struct device *dev = &client->dev;
+       const struct firmware *fw;
+       s32 status;
+       unsigned int offset, len, xfer_len;
+       unsigned int retry = 0;
+       int error, error2;
+
+       error = request_firmware(&fw, firmware_name, dev);
+       if (error) {
+               dev_err(dev, "unable to retrieve firmware %s: %d\n",
+                       firmware_name, error);
+               return error;
+       }
+
+       error = i2c_smbus_write_byte_data(client, INT_MASK,
+                                         COORD_UPDATE | CALIBRATION_DONE |
+                                         SLEEP_IN | SLEEP_OUT);
+       if (error)
+               goto out;
+
+       do {
+               if (retry) {
+                       dev_warn(dev, "retrying firmware load\n");
+
+                       /* settings for retry */
+                       error = i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+                       if (error)
+                               goto out;
+               }
+
+               error = i2c_smbus_write_byte_data(client, EX_ADDR_H, 0);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client, EX_ADDR_L, 0);
+               if (error)
+                       goto out;
+
+               error = i2c_smbus_write_byte_data(client, COMMON_SETUP1,
+                                                 COMMON_SETUP1_DEFAULT);
+               if (error)
+                       goto out;
+
+               /* firmware load to the device */
+               offset = 0;
+               len = fw->size;
+
+               while (len) {
+                       xfer_len = min(FIRMWARE_BLOCK_SIZE, len);
+
+                       error = i2c_smbus_write_i2c_block_data(client, EX_WDAT,
+                                               xfer_len, &fw->data[offset]);
+                       if (error)
+                               goto out;
+
+                       len -= xfer_len;
+                       offset += xfer_len;
+               }
+
+               /* check firmware load result */
+               status = i2c_smbus_read_byte_data(client, INT_STATUS);
+               if (status < 0) {
+                       error = status;
+                       goto out;
+               }
+
+               /* clear all interrupts */
+               error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+               if (error)
+                       goto out;
+
+               if (status == PROGRAM_LOAD_DONE)
+                       break;
+
+               error = -EIO;
+       } while (++retry >= FIRMWARE_RETRY_MAX);
+
+out:
+       error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+
+       release_firmware(fw);
+
+       return error ? error : error2;
+}
+
+static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
+}
+
+static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+       unsigned int val;
+       int error;
+
+       error = kstrtouint(buf, 0, &val);
+       if (error)
+               return error;
+
+       error = mutex_lock_interruptible(&ts->input->mutex);
+       if (error)
+               return error;
+
+       if (val)
+               ts->setup2 |= SWAP_XY;
+       else
+               ts->setup2 &= ~SWAP_XY;
+
+       if (ts->initialized)
+               error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
+                                                 ts->setup2);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return error ? error : count;
+}
+
+static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X));
+}
+
+static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+       unsigned int val;
+       int error;
+
+       error = kstrtouint(buf, 0, &val);
+       if (error)
+               return error;
+
+       error = mutex_lock_interruptible(&ts->input->mutex);
+       if (error)
+               return error;
+
+       if (val)
+               ts->setup2 |= INV_X;
+       else
+               ts->setup2 &= ~INV_X;
+
+       if (ts->initialized)
+               error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
+                                                 ts->setup2);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return error ? error : count;
+}
+
+static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y));
+}
+
+static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rohm_ts_data *ts = i2c_get_clientdata(client);
+       unsigned int val;
+       int error;
+
+       error = kstrtouint(buf, 0, &val);
+       if (error)
+               return error;
+
+       error = mutex_lock_interruptible(&ts->input->mutex);
+       if (error)
+               return error;
+
+       if (val)
+               ts->setup2 |= INV_Y;
+       else
+               ts->setup2 &= ~INV_Y;
+
+       if (ts->initialized)
+               error = i2c_smbus_write_byte_data(client, COMMON_SETUP2,
+                                                 ts->setup2);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return error ? error : count;
+}
+
+static DEVICE_ATTR_RW(swap_xy);
+static DEVICE_ATTR_RW(inv_x);
+static DEVICE_ATTR_RW(inv_y);
+
+static struct attribute *rohm_ts_attrs[] = {
+       &dev_attr_swap_xy.attr,
+       &dev_attr_inv_x.attr,
+       &dev_attr_inv_y.attr,
+       NULL,
+};
+
+static const struct attribute_group rohm_ts_attr_group = {
+       .attrs = rohm_ts_attrs,
+};
+
+static int rohm_ts_device_init(struct i2c_client *client, u8 setup2)
+{
+       struct device *dev = &client->dev;
+       int error;
+
+       disable_irq(client->irq);
+
+       /*
+        * Wait 200usec for reset
+        */
+       udelay(200);
+
+       /* Release analog reset */
+       error = i2c_smbus_write_byte_data(client, SYSTEM,
+                                         ANALOG_POWER_ON | CPU_POWER_OFF);
+       if (error)
+               return error;
+
+       /* Waiting for the analog warm-up, max. 200usec */
+       udelay(200);
+
+       /* clear all interrupts */
+       error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, COMMON_SETUP2, setup2);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, COMMON_SETUP3,
+                                         SEL_TBL_DEFAULT | EN_MULTI);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE,
+                                         THRESHOLD_GESTURE_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, INTERVAL_TIME,
+                                         INTERVAL_TIME_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME,
+                                         PRM_SWOFF_TIME_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT);
+       if (error)
+               return error;
+
+       /*
+        * Panel setup, these values change with the panel.
+        */
+       error = i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH,
+                                         THRESHOLD_TOUCH_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT);
+       if (error)
+               return error;
+
+       /* Fixed value settings */
+       error = i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST,
+                                         CALIBRATION_ADJUST_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, TEST1,
+                                         DUALTOUCH_STABILIZE_ON |
+                                         DUALTOUCH_REG_ON);
+       if (error)
+               return error;
+
+       error = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME);
+       if (error) {
+               dev_err(dev, "failed to load firmware: %d\n", error);
+               return error;
+       }
+
+       /*
+        * Manual calibration results are not changed in same environment.
+        * If the force calibration is performed,
+        * the controller will not require calibration request interrupt
+        * when the typical values are set to the calibration registers.
+        */
+       error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
+                                         CALIBRATION_REG1_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
+                                         CALIBRATION_REG2_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
+                                         CALIBRATION_REG3_DEFAULT);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+                                         FORCE_CALIBRATION_OFF);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+                                         FORCE_CALIBRATION_ON);
+       if (error)
+               return error;
+
+       /* Clear all interrupts */
+       error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+       if (error)
+               return error;
+
+       /* Enable coordinates update interrupt */
+       error = i2c_smbus_write_byte_data(client, INT_MASK,
+                                         CALIBRATION_DONE | SLEEP_OUT |
+                                         SLEEP_IN | PROGRAM_LOAD_DONE);
+       if (error)
+               return error;
+
+       error = i2c_smbus_write_byte_data(client, ERR_MASK,
+                                         PROGRAM_LOAD_ERR | CPU_TIMEOUT |
+                                         ADC_TIMEOUT);
+       if (error)
+               return error;
+
+       /* controller CPU power on */
+       error = i2c_smbus_write_byte_data(client, SYSTEM,
+                                         ANALOG_POWER_ON | CPU_POWER_ON);
+
+       enable_irq(client->irq);
+
+       return error;
+}
+
+static int rohm_ts_power_off(struct i2c_client *client)
+{
+       int error;
+
+       error = i2c_smbus_write_byte_data(client, SYSTEM,
+                                         ANALOG_POWER_ON | CPU_POWER_OFF);
+       if (error) {
+               dev_err(&client->dev,
+                       "failed to power off device CPU: %d\n", error);
+               return error;
+       }
+
+       error = i2c_smbus_write_byte_data(client, SYSTEM,
+                                         ANALOG_POWER_OFF | CPU_POWER_OFF);
+       if (error)
+               dev_err(&client->dev,
+                       "failed to power off the device: %d\n", error);
+
+       return error;
+}
+
+static int rohm_ts_open(struct input_dev *input_dev)
+{
+       struct rohm_ts_data *ts = input_get_drvdata(input_dev);
+       struct i2c_client *client = ts->client;
+       int error;
+
+       if (!ts->initialized) {
+               error = rohm_ts_device_init(client, ts->setup2);
+               if (error) {
+                       dev_err(&client->dev,
+                               "device initialization failed: %d\n", error);
+                       return error;
+               }
+
+               ts->initialized = true;
+       }
+
+       return 0;
+}
+
+static void rohm_ts_close(struct input_dev *input_dev)
+{
+       struct rohm_ts_data *ts = input_get_drvdata(input_dev);
+
+       rohm_ts_power_off(ts->client);
+
+       ts->initialized = false;
+}
+
+static void rohm_ts_remove_sysfs_group(void *_dev)
+{
+       struct device *dev = _dev;
+
+       sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group);
+}
+
+static int rohm_bu21023_i2c_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct rohm_ts_data *ts;
+       struct input_dev *input;
+       int error;
+
+       if (!client->irq) {
+               dev_err(dev, "IRQ is not assigned\n");
+               return -EINVAL;
+       }
+
+       if (!client->adapter->algo->master_xfer) {
+               dev_err(dev, "I2C level transfers not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Turn off CPU just in case */
+       error = rohm_ts_power_off(client);
+       if (error)
+               return error;
+
+       ts = devm_kzalloc(dev, sizeof(struct rohm_ts_data), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       ts->client = client;
+       ts->setup2 = MAF_1SAMPLE;
+       i2c_set_clientdata(client, ts);
+
+       input = devm_input_allocate_device(dev);
+       if (!input)
+               return -ENOMEM;
+
+       input->name = BU21023_NAME;
+       input->id.bustype = BUS_I2C;
+       input->open = rohm_ts_open;
+       input->close = rohm_ts_close;
+
+       ts->input = input;
+       input_set_drvdata(input, ts);
+
+       input_set_abs_params(input, ABS_MT_POSITION_X,
+                            ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y,
+                            ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0);
+
+       error = input_mt_init_slots(input, MAX_CONTACTS,
+                                   INPUT_MT_DIRECT | INPUT_MT_TRACK |
+                                   INPUT_MT_DROP_UNUSED);
+       if (error) {
+               dev_err(dev, "failed to multi touch slots initialization\n");
+               return error;
+       }
+
+       error = devm_request_threaded_irq(dev, client->irq,
+                                         NULL, rohm_ts_soft_irq,
+                                         IRQF_ONESHOT, client->name, ts);
+       if (error) {
+               dev_err(dev, "failed to request IRQ: %d\n", error);
+               return error;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(dev, "failed to register input device: %d\n", error);
+               return error;
+       }
+
+       error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group);
+       if (error) {
+               dev_err(dev, "failed to create sysfs group: %d\n", error);
+               return error;
+       }
+
+       error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev);
+       if (error) {
+               rohm_ts_remove_sysfs_group(dev);
+               dev_err(&client->dev,
+                       "Failed to add sysfs cleanup action: %d\n",
+                       error);
+               return error;
+       }
+
+       return error;
+}
+
+static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
+       { BU21023_NAME, 0 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
+
+static struct i2c_driver rohm_bu21023_i2c_driver = {
+       .driver = {
+               .name = BU21023_NAME,
+       },
+       .probe = rohm_bu21023_i2c_probe,
+       .id_table = rohm_bu21023_i2c_id,
+};
+module_i2c_driver(rohm_bu21023_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("ROHM Co., Ltd.");
index 4ffd829d1990a2d0e66d8c7fdf0fa2151f6c0504..a340bfccdfb6697fb033dca488f310559ba91fd6 100644 (file)
@@ -50,14 +50,7 @@ struct tps6507x_ts {
 
 static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
 {
-       int err;
-
-       err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
-
-       if (err)
-               return err;
-
-       return 0;
+       return tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
 }
 
 static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data)
index 781d0f83050ab005ef4917188f2df0e3995aad72..9bbadaaf6bc3723f044a9c44e8619773d242ec8f 100644 (file)
@@ -599,13 +599,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
 static int zforce_input_open(struct input_dev *dev)
 {
        struct zforce_ts *ts = input_get_drvdata(dev);
-       int ret;
 
-       ret = zforce_start(ts);
-       if (ret)
-               return ret;
-
-       return 0;
+       return zforce_start(ts);
 }
 
 static void zforce_input_close(struct input_dev *dev)
index bbec5009cdc2b8bd7d82612a17c07805d845575b..546d05f4358a7c452ee80366b3ae782e685fd7ef 100644 (file)
@@ -71,4 +71,18 @@ config BCM2835_MBOX
          the services of the Videocore. Say Y here if you want to use the
          BCM2835 Mailbox.
 
+config STI_MBOX
+       tristate "STI Mailbox framework support"
+       depends on ARCH_STI && OF
+       help
+         Mailbox implementation for STMicroelectonics family chips with
+         hardware for interprocessor communication.
+
+config MAILBOX_TEST
+       tristate "Mailbox Test Client"
+       depends on OF
+       help
+         Test client to help with testing new Controller driver
+         implementations.
+
 endif
index 8e6d82218a09422d7849e5e83dbd19324e593763..92435ef11f26868c48f4be24a9d36eeb80b58061 100644 (file)
@@ -2,6 +2,8 @@
 
 obj-$(CONFIG_MAILBOX)          += mailbox.o
 
+obj-$(CONFIG_MAILBOX_TEST)     += mailbox-test.o
+
 obj-$(CONFIG_ARM_MHU)  += arm_mhu.o
 
 obj-$(CONFIG_PL320_MBOX)       += pl320-ipc.o
@@ -13,3 +15,5 @@ obj-$(CONFIG_PCC)             += pcc.o
 obj-$(CONFIG_ALTERA_MBOX)      += mailbox-altera.o
 
 obj-$(CONFIG_BCM2835_MBOX)     += bcm2835-mailbox.o
+
+obj-$(CONFIG_STI_MBOX)         += mailbox-sti.o
diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c
new file mode 100644 (file)
index 0000000..4835817
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * STi Mailbox
+ *
+ * Copyright (C) 2015 ST Microelectronics
+ *
+ * Author: Lee Jones <lee.jones@linaro.org> for ST Microelectronics
+ *
+ * Based on the original driver written by;
+ *   Alexandre Torgue, Olivier Lebreton and Loic Pallardy
+ *
+ * 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "mailbox.h"
+
+#define STI_MBOX_INST_MAX      4      /* RAM saving: Max supported instances */
+#define STI_MBOX_CHAN_MAX      20     /* RAM saving: Max supported channels  */
+
+#define STI_IRQ_VAL_OFFSET     0x04   /* Read interrupt status               */
+#define STI_IRQ_SET_OFFSET     0x24   /* Generate a Tx channel interrupt     */
+#define STI_IRQ_CLR_OFFSET     0x44   /* Clear pending Rx interrupts         */
+#define STI_ENA_VAL_OFFSET     0x64   /* Read enable status                  */
+#define STI_ENA_SET_OFFSET     0x84   /* Enable a channel                    */
+#define STI_ENA_CLR_OFFSET     0xa4   /* Disable a channel                   */
+
+#define MBOX_BASE(mdev, inst)   ((mdev)->base + ((inst) * 4))
+
+/**
+ * STi Mailbox device data
+ *
+ * An IP Mailbox is currently composed of 4 instances
+ * Each instance is currently composed of 32 channels
+ * This means that we have 128 channels per Mailbox
+ * A channel an be used for TX or RX
+ *
+ * @dev:       Device to which it is attached
+ * @mbox:      Representation of a communication channel controller
+ * @base:      Base address of the register mapping region
+ * @name:      Name of the mailbox
+ * @enabled:   Local copy of enabled channels
+ * @lock:      Mutex protecting enabled status
+ */
+struct sti_mbox_device {
+       struct device           *dev;
+       struct mbox_controller  *mbox;
+       void __iomem            *base;
+       const char              *name;
+       u32                     enabled[STI_MBOX_INST_MAX];
+       spinlock_t              lock;
+};
+
+/**
+ * STi Mailbox platform specific configuration
+ *
+ * @num_inst:  Maximum number of instances in one HW Mailbox
+ * @num_chan:  Maximum number of channel per instance
+ */
+struct sti_mbox_pdata {
+       unsigned int            num_inst;
+       unsigned int            num_chan;
+};
+
+/**
+ * STi Mailbox allocated channel information
+ *
+ * @mdev:      Pointer to parent Mailbox device
+ * @instance:  Instance number channel resides in
+ * @channel:   Channel number pertaining to this container
+ */
+struct sti_channel {
+       struct sti_mbox_device  *mdev;
+       unsigned int            instance;
+       unsigned int            channel;
+};
+
+static inline bool sti_mbox_channel_is_enabled(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+
+       return mdev->enabled[instance] & BIT(channel);
+}
+
+static inline
+struct mbox_chan *sti_mbox_to_channel(struct mbox_controller *mbox,
+                                     unsigned int instance,
+                                     unsigned int channel)
+{
+       struct sti_channel *chan_info;
+       int i;
+
+       for (i = 0; i < mbox->num_chans; i++) {
+               chan_info = mbox->chans[i].con_priv;
+               if (chan_info &&
+                   chan_info->instance == instance &&
+                   chan_info->channel == channel)
+                       return &mbox->chans[i];
+       }
+
+       dev_err(mbox->dev,
+               "Channel not registered: instance: %d channel: %d\n",
+               instance, channel);
+
+       return NULL;
+}
+
+static void sti_mbox_enable_channel(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+       unsigned long flags;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       spin_lock_irqsave(&mdev->lock, flags);
+       mdev->enabled[instance] |= BIT(channel);
+       writel_relaxed(BIT(channel), base + STI_ENA_SET_OFFSET);
+       spin_unlock_irqrestore(&mdev->lock, flags);
+}
+
+static void sti_mbox_disable_channel(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+       unsigned long flags;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       spin_lock_irqsave(&mdev->lock, flags);
+       mdev->enabled[instance] &= ~BIT(channel);
+       writel_relaxed(BIT(channel), base + STI_ENA_CLR_OFFSET);
+       spin_unlock_irqrestore(&mdev->lock, flags);
+}
+
+static void sti_mbox_clear_irq(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       writel_relaxed(BIT(channel), base + STI_IRQ_CLR_OFFSET);
+}
+
+static struct mbox_chan *sti_mbox_irq_to_channel(struct sti_mbox_device *mdev,
+                                                unsigned int instance)
+{
+       struct mbox_controller *mbox = mdev->mbox;
+       struct mbox_chan *chan = NULL;
+       unsigned int channel;
+       unsigned long bits;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       bits = readl_relaxed(base + STI_IRQ_VAL_OFFSET);
+       if (!bits)
+               /* No IRQs fired in specified instance */
+               return NULL;
+
+       /* An IRQ has fired, find the associated channel */
+       for (channel = 0; bits; channel++) {
+               if (!test_and_clear_bit(channel, &bits))
+                       continue;
+
+               chan = sti_mbox_to_channel(mbox, instance, channel);
+               if (chan) {
+                       dev_dbg(mbox->dev,
+                               "IRQ fired on instance: %d channel: %d\n",
+                               instance, channel);
+                       break;
+               }
+       }
+
+       return chan;
+}
+
+static irqreturn_t sti_mbox_thread_handler(int irq, void *data)
+{
+       struct sti_mbox_device *mdev = data;
+       struct sti_mbox_pdata *pdata = dev_get_platdata(mdev->dev);
+       struct mbox_chan *chan;
+       unsigned int instance;
+
+       for (instance = 0; instance < pdata->num_inst; instance++) {
+keep_looking:
+               chan = sti_mbox_irq_to_channel(mdev, instance);
+               if (!chan)
+                       continue;
+
+               mbox_chan_received_data(chan, NULL);
+               sti_mbox_clear_irq(chan);
+               sti_mbox_enable_channel(chan);
+               goto keep_looking;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sti_mbox_irq_handler(int irq, void *data)
+{
+       struct sti_mbox_device *mdev = data;
+       struct sti_mbox_pdata *pdata = dev_get_platdata(mdev->dev);
+       struct sti_channel *chan_info;
+       struct mbox_chan *chan;
+       unsigned int instance;
+       int ret = IRQ_NONE;
+
+       for (instance = 0; instance < pdata->num_inst; instance++) {
+               chan = sti_mbox_irq_to_channel(mdev, instance);
+               if (!chan)
+                       continue;
+               chan_info = chan->con_priv;
+
+               if (!sti_mbox_channel_is_enabled(chan)) {
+                       dev_warn(mdev->dev,
+                                "Unexpected IRQ: %s\n"
+                                "  instance: %d: channel: %d [enabled: %x]\n",
+                                mdev->name, chan_info->instance,
+                                chan_info->channel, mdev->enabled[instance]);
+
+                       /* Only handle IRQ if no other valid IRQs were found */
+                       if (ret == IRQ_NONE)
+                               ret = IRQ_HANDLED;
+                       continue;
+               }
+
+               sti_mbox_disable_channel(chan);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       if (ret == IRQ_NONE)
+               dev_err(mdev->dev, "Spurious IRQ - was a channel requested?\n");
+
+       return ret;
+}
+
+static bool sti_mbox_tx_is_ready(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       if (!(readl_relaxed(base + STI_ENA_VAL_OFFSET) & BIT(channel))) {
+               dev_dbg(mdev->dev, "Mbox: %s: inst: %d, chan: %d disabled\n",
+                       mdev->name, instance, channel);
+               return false;
+       }
+
+       if (readl_relaxed(base + STI_IRQ_VAL_OFFSET) & BIT(channel)) {
+               dev_dbg(mdev->dev, "Mbox: %s: inst: %d, chan: %d not ready\n",
+                       mdev->name, instance, channel);
+               return false;
+       }
+
+       return true;
+}
+
+static int sti_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct sti_mbox_device *mdev = chan_info->mdev;
+       unsigned int instance = chan_info->instance;
+       unsigned int channel = chan_info->channel;
+       void __iomem *base = MBOX_BASE(mdev, instance);
+
+       /* Send event to co-processor */
+       writel_relaxed(BIT(channel), base + STI_IRQ_SET_OFFSET);
+
+       dev_dbg(mdev->dev,
+               "Sent via Mailbox %s: instance: %d channel: %d\n",
+               mdev->name, instance, channel);
+
+       return 0;
+}
+
+static int sti_mbox_startup_chan(struct mbox_chan *chan)
+{
+       sti_mbox_clear_irq(chan);
+       sti_mbox_enable_channel(chan);
+
+       return 0;
+}
+
+static void sti_mbox_shutdown_chan(struct mbox_chan *chan)
+{
+       struct sti_channel *chan_info = chan->con_priv;
+       struct mbox_controller *mbox = chan_info->mdev->mbox;
+       int i;
+
+       for (i = 0; i < mbox->num_chans; i++)
+               if (chan == &mbox->chans[i])
+                       break;
+
+       if (mbox->num_chans == i) {
+               dev_warn(mbox->dev, "Request to free non-existent channel\n");
+               return;
+       }
+
+       /* Reset channel */
+       sti_mbox_disable_channel(chan);
+       sti_mbox_clear_irq(chan);
+       chan->con_priv = NULL;
+}
+
+static struct mbox_chan *sti_mbox_xlate(struct mbox_controller *mbox,
+                                       const struct of_phandle_args *spec)
+{
+       struct sti_mbox_device *mdev = dev_get_drvdata(mbox->dev);
+       struct sti_mbox_pdata *pdata = dev_get_platdata(mdev->dev);
+       struct sti_channel *chan_info;
+       struct mbox_chan *chan = NULL;
+       unsigned int instance  = spec->args[0];
+       unsigned int channel   = spec->args[1];
+       int i;
+
+       /* Bounds checking */
+       if (instance >= pdata->num_inst || channel  >= pdata->num_chan) {
+               dev_err(mbox->dev,
+                       "Invalid channel requested instance: %d channel: %d\n",
+                       instance, channel);
+               return ERR_PTR(-EINVAL);
+       }
+
+       for (i = 0; i < mbox->num_chans; i++) {
+               chan_info = mbox->chans[i].con_priv;
+
+               /* Is requested channel free? */
+               if (chan_info &&
+                   mbox->dev == chan_info->mdev->dev &&
+                   instance == chan_info->instance &&
+                   channel == chan_info->channel) {
+
+                       dev_err(mbox->dev, "Channel in use\n");
+                       return ERR_PTR(-EBUSY);
+               }
+
+               /*
+                * Find the first free slot, then continue checking
+                * to see if requested channel is in use
+                */
+               if (!chan && !chan_info)
+                       chan = &mbox->chans[i];
+       }
+
+       if (!chan) {
+               dev_err(mbox->dev, "No free channels left\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       chan_info = devm_kzalloc(mbox->dev, sizeof(*chan_info), GFP_KERNEL);
+       if (!chan_info)
+               return ERR_PTR(-ENOMEM);
+
+       chan_info->mdev         = mdev;
+       chan_info->instance     = instance;
+       chan_info->channel      = channel;
+
+       chan->con_priv = chan_info;
+
+       dev_info(mbox->dev,
+                "Mbox: %s: Created channel: instance: %d channel: %d\n",
+                mdev->name, instance, channel);
+
+       return chan;
+}
+
+static struct mbox_chan_ops sti_mbox_ops = {
+       .startup        = sti_mbox_startup_chan,
+       .shutdown       = sti_mbox_shutdown_chan,
+       .send_data      = sti_mbox_send_data,
+       .last_tx_done   = sti_mbox_tx_is_ready,
+};
+
+static const struct sti_mbox_pdata mbox_stih407_pdata = {
+       .num_inst       = 4,
+       .num_chan       = 32,
+};
+
+static const struct of_device_id sti_mailbox_match[] = {
+       {
+               .compatible = "st,stih407-mailbox",
+               .data = (void *)&mbox_stih407_pdata
+       },
+       { }
+};
+
+static int sti_mbox_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct mbox_controller *mbox;
+       struct sti_mbox_device *mdev;
+       struct device_node *np = pdev->dev.of_node;
+       struct mbox_chan *chans;
+       struct resource *res;
+       int irq;
+       int ret;
+
+       match = of_match_device(sti_mailbox_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "No configuration found\n");
+               return -ENODEV;
+       }
+       pdev->dev.platform_data = (struct sti_mbox_pdata *) match->data;
+
+       mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+       if (!mdev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mdev);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mdev->base = devm_ioremap_resource(&pdev->dev, res);
+       if (!mdev->base)
+               return -ENOMEM;
+
+       ret = of_property_read_string(np, "mbox-name", &mdev->name);
+       if (ret)
+               mdev->name = np->full_name;
+
+       mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       chans = devm_kzalloc(&pdev->dev,
+                            sizeof(*chans) * STI_MBOX_CHAN_MAX, GFP_KERNEL);
+       if (!chans)
+               return -ENOMEM;
+
+       mdev->dev               = &pdev->dev;
+       mdev->mbox              = mbox;
+
+       spin_lock_init(&mdev->lock);
+
+       /* STi Mailbox does not have a Tx-Done or Tx-Ready IRQ */
+       mbox->txdone_irq        = false;
+       mbox->txdone_poll       = true;
+       mbox->txpoll_period     = 100;
+       mbox->ops               = &sti_mbox_ops;
+       mbox->dev               = mdev->dev;
+       mbox->of_xlate          = sti_mbox_xlate;
+       mbox->chans             = chans;
+       mbox->num_chans         = STI_MBOX_CHAN_MAX;
+
+       ret = mbox_controller_register(mbox);
+       if (ret)
+               return ret;
+
+       /* It's okay for Tx Mailboxes to not supply IRQs */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_info(&pdev->dev,
+                        "%s: Registered Tx only Mailbox\n", mdev->name);
+               return 0;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, irq,
+                                       sti_mbox_irq_handler,
+                                       sti_mbox_thread_handler,
+                                       IRQF_ONESHOT, mdev->name, mdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't claim IRQ %d\n", irq);
+               mbox_controller_unregister(mbox);
+               return -EINVAL;
+       }
+
+       dev_info(&pdev->dev, "%s: Registered Tx/Rx Mailbox\n", mdev->name);
+
+       return 0;
+}
+
+static int sti_mbox_remove(struct platform_device *pdev)
+{
+       struct sti_mbox_device *mdev = platform_get_drvdata(pdev);
+
+       mbox_controller_unregister(mdev->mbox);
+
+       return 0;
+}
+
+static struct platform_driver sti_mbox_driver = {
+       .probe = sti_mbox_probe,
+       .remove = sti_mbox_remove,
+       .driver = {
+               .name = "sti-mailbox",
+               .of_match_table = sti_mailbox_match,
+       },
+};
+module_platform_driver(sti_mbox_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STMicroelectronics Mailbox Controller");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
+MODULE_ALIAS("platform:mailbox-sti");
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
new file mode 100644 (file)
index 0000000..684ae17
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2015 ST Microelectronics
+ *
+ * Author: Lee Jones <lee.jones@linaro.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.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#define MBOX_MAX_SIG_LEN       8
+#define MBOX_MAX_MSG_LEN       128
+#define MBOX_BYTES_PER_LINE    16
+#define MBOX_HEXDUMP_LINE_LEN  ((MBOX_BYTES_PER_LINE * 4) + 2)
+#define MBOX_HEXDUMP_MAX_LEN   (MBOX_HEXDUMP_LINE_LEN *                \
+                                (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
+
+static struct dentry *root_debugfs_dir;
+
+struct mbox_test_device {
+       struct device           *dev;
+       void __iomem            *mmio;
+       struct mbox_chan        *tx_channel;
+       struct mbox_chan        *rx_channel;
+       char                    *rx_buffer;
+       char                    *signal;
+       char                    *message;
+       spinlock_t              lock;
+};
+
+static ssize_t mbox_test_signal_write(struct file *filp,
+                                      const char __user *userbuf,
+                                      size_t count, loff_t *ppos)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+       int ret;
+
+       if (!tdev->tx_channel) {
+               dev_err(tdev->dev, "Channel cannot do Tx\n");
+               return -EINVAL;
+       }
+
+       if (count > MBOX_MAX_SIG_LEN) {
+               dev_err(tdev->dev,
+                       "Signal length %zd greater than max allowed %d\n",
+                       count, MBOX_MAX_SIG_LEN);
+               return -EINVAL;
+       }
+
+       tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
+       if (!tdev->signal)
+               return -ENOMEM;
+
+       ret = copy_from_user(tdev->signal, userbuf, count);
+       if (ret) {
+               kfree(tdev->signal);
+               return -EFAULT;
+       }
+
+       return ret < 0 ? ret : count;
+}
+
+static const struct file_operations mbox_test_signal_ops = {
+       .write  = mbox_test_signal_write,
+       .open   = simple_open,
+       .llseek = generic_file_llseek,
+};
+
+static ssize_t mbox_test_message_write(struct file *filp,
+                                      const char __user *userbuf,
+                                      size_t count, loff_t *ppos)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+       void *data;
+       int ret;
+
+       if (!tdev->tx_channel) {
+               dev_err(tdev->dev, "Channel cannot do Tx\n");
+               return -EINVAL;
+       }
+
+       if (count > MBOX_MAX_MSG_LEN) {
+               dev_err(tdev->dev,
+                       "Message length %zd greater than max allowed %d\n",
+                       count, MBOX_MAX_MSG_LEN);
+               return -EINVAL;
+       }
+
+       tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
+       if (!tdev->message)
+               return -ENOMEM;
+
+       ret = copy_from_user(tdev->message, userbuf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /*
+        * A separate signal is only of use if there is
+        * MMIO to subsequently pass the message through
+        */
+       if (tdev->mmio && tdev->signal) {
+               print_hex_dump(KERN_INFO, "Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
+                              MBOX_BYTES_PER_LINE, 1, tdev->signal, MBOX_MAX_SIG_LEN, true);
+
+               data = tdev->signal;
+       } else
+               data = tdev->message;
+
+       print_hex_dump(KERN_INFO, "Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
+                      MBOX_BYTES_PER_LINE, 1, tdev->message, MBOX_MAX_MSG_LEN, true);
+
+       ret = mbox_send_message(tdev->tx_channel, data);
+       if (ret < 0)
+               dev_err(tdev->dev, "Failed to send message via mailbox\n");
+
+out:
+       kfree(tdev->signal);
+       kfree(tdev->message);
+
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
+                                     size_t count, loff_t *ppos)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+       unsigned long flags;
+       char *touser, *ptr;
+       int l = 0;
+       int ret;
+
+       touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
+       if (!touser)
+               return -ENOMEM;
+
+       if (!tdev->rx_channel) {
+               ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
+               ret = simple_read_from_buffer(userbuf, count, ppos,
+                                             touser, ret);
+               goto out;
+       }
+
+       if (tdev->rx_buffer[0] == '\0') {
+               ret = snprintf(touser, 9, "<EMPTY>\n");
+               ret = simple_read_from_buffer(userbuf, count, ppos,
+                                             touser, ret);
+               goto out;
+       }
+
+       spin_lock_irqsave(&tdev->lock, flags);
+
+       ptr = tdev->rx_buffer;
+       while (l < MBOX_HEXDUMP_MAX_LEN) {
+               hex_dump_to_buffer(ptr,
+                                  MBOX_BYTES_PER_LINE,
+                                  MBOX_BYTES_PER_LINE, 1, touser + l,
+                                  MBOX_HEXDUMP_LINE_LEN, true);
+
+               ptr += MBOX_BYTES_PER_LINE;
+               l += MBOX_HEXDUMP_LINE_LEN;
+               *(touser + (l - 1)) = '\n';
+       }
+       *(touser + l) = '\0';
+
+       memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
+
+       spin_unlock_irqrestore(&tdev->lock, flags);
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
+out:
+       kfree(touser);
+       return ret;
+}
+
+static const struct file_operations mbox_test_message_ops = {
+       .write  = mbox_test_message_write,
+       .read   = mbox_test_message_read,
+       .open   = simple_open,
+       .llseek = generic_file_llseek,
+};
+
+static int mbox_test_add_debugfs(struct platform_device *pdev,
+                                struct mbox_test_device *tdev)
+{
+       if (!debugfs_initialized())
+               return 0;
+
+       root_debugfs_dir = debugfs_create_dir("mailbox", NULL);
+       if (!root_debugfs_dir) {
+               dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
+               return -EINVAL;
+       }
+
+       debugfs_create_file("message", 0600, root_debugfs_dir,
+                           tdev, &mbox_test_message_ops);
+
+       debugfs_create_file("signal", 0200, root_debugfs_dir,
+                           tdev, &mbox_test_signal_ops);
+
+       return 0;
+}
+
+static void mbox_test_receive_message(struct mbox_client *client, void *message)
+{
+       struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tdev->lock, flags);
+       if (tdev->mmio) {
+               memcpy_fromio(tdev->rx_buffer, tdev->mmio, MBOX_MAX_MSG_LEN);
+               print_hex_dump(KERN_INFO, "Client: Received [MMIO]: ",
+                              DUMP_PREFIX_ADDRESS, MBOX_BYTES_PER_LINE, 1,
+                              tdev->rx_buffer, MBOX_MAX_MSG_LEN, true);
+       } else if (message) {
+               print_hex_dump(KERN_INFO, "Client: Received [API]: ",
+                              DUMP_PREFIX_ADDRESS, MBOX_BYTES_PER_LINE, 1,
+                              message, MBOX_MAX_MSG_LEN, true);
+               memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
+       }
+       spin_unlock_irqrestore(&tdev->lock, flags);
+}
+
+static void mbox_test_prepare_message(struct mbox_client *client, void *message)
+{
+       struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
+
+       if (tdev->mmio) {
+               if (tdev->signal)
+                       memcpy_toio(tdev->mmio, tdev->message, MBOX_MAX_MSG_LEN);
+               else
+                       memcpy_toio(tdev->mmio, message, MBOX_MAX_MSG_LEN);
+       }
+}
+
+static void mbox_test_message_sent(struct mbox_client *client,
+                                  void *message, int r)
+{
+       if (r)
+               dev_warn(client->dev,
+                        "Client: Message could not be sent: %d\n", r);
+       else
+               dev_info(client->dev,
+                        "Client: Message sent\n");
+}
+
+static struct mbox_chan *
+mbox_test_request_channel(struct platform_device *pdev, const char *name)
+{
+       struct mbox_client *client;
+       struct mbox_chan *channel;
+
+       client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return ERR_PTR(-ENOMEM);
+
+       client->dev             = &pdev->dev;
+       client->rx_callback     = mbox_test_receive_message;
+       client->tx_prepare      = mbox_test_prepare_message;
+       client->tx_done         = mbox_test_message_sent;
+       client->tx_block        = true;
+       client->knows_txdone    = false;
+       client->tx_tout         = 500;
+
+       channel = mbox_request_channel_byname(client, name);
+       if (IS_ERR(channel)) {
+               dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
+               return NULL;
+       }
+
+       return channel;
+}
+
+static int mbox_test_probe(struct platform_device *pdev)
+{
+       struct mbox_test_device *tdev;
+       struct resource *res;
+       int ret;
+
+       tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
+       if (!tdev)
+               return -ENOMEM;
+
+       /* It's okay for MMIO to be NULL */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       tdev->mmio = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(tdev->mmio))
+               tdev->mmio = NULL;
+
+       tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
+       tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
+
+       if (!tdev->tx_channel && !tdev->rx_channel)
+               return -EPROBE_DEFER;
+
+       tdev->dev = &pdev->dev;
+       platform_set_drvdata(pdev, tdev);
+
+       spin_lock_init(&tdev->lock);
+
+       if (tdev->rx_channel) {
+               tdev->rx_buffer = devm_kzalloc(&pdev->dev,
+                                              MBOX_MAX_MSG_LEN, GFP_KERNEL);
+               if (!tdev->rx_buffer)
+                       return -ENOMEM;
+       }
+
+       ret = mbox_test_add_debugfs(pdev, tdev);
+       if (ret)
+               return ret;
+
+       dev_info(&pdev->dev, "Successfully registered\n");
+
+       return 0;
+}
+
+static int mbox_test_remove(struct platform_device *pdev)
+{
+       struct mbox_test_device *tdev = platform_get_drvdata(pdev);
+
+       debugfs_remove_recursive(root_debugfs_dir);
+
+       if (tdev->tx_channel)
+               mbox_free_channel(tdev->tx_channel);
+       if (tdev->rx_channel)
+               mbox_free_channel(tdev->rx_channel);
+
+       return 0;
+}
+
+static const struct of_device_id mbox_test_match[] = {
+       { .compatible = "mailbox_test" },
+       {},
+};
+
+static struct platform_driver mbox_test_driver = {
+       .driver = {
+               .name = "mailbox_sti_test",
+               .of_match_table = mbox_test_match,
+       },
+       .probe  = mbox_test_probe,
+       .remove = mbox_test_remove,
+};
+module_platform_driver(mbox_test_driver);
+
+MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
+MODULE_LICENSE("GPL v2");
index a3dbfd9c647994ec6794701cfc25a327739640ad..b7f636f15cac284028cd7039c82470deaffe2f95 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/mailbox_controller.h>
 #include <linux/mailbox_client.h>
 
+#include "mailbox.h"
+
 #define MAILBOX_REVISION               0x000
 #define MAILBOX_MESSAGE(m)             (0x040 + 4 * (m))
 #define MAILBOX_FIFOSTATUS(m)          (0x080 + 4 * (m))
@@ -106,6 +108,7 @@ struct omap_mbox_fifo_info {
        int rx_irq;
 
        const char *name;
+       bool send_no_irq;
 };
 
 struct omap_mbox {
@@ -119,6 +122,7 @@ struct omap_mbox {
        u32                     ctx[OMAP4_MBOX_NR_REGS];
        u32                     intr_type;
        struct mbox_chan        *chan;
+       bool                    send_no_irq;
 };
 
 /* global variables for the mailbox devices */
@@ -418,6 +422,9 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
                goto fail_request_irq;
        }
 
+       if (mbox->send_no_irq)
+               mbox->chan->txdone_method = TXDONE_BY_ACK;
+
        _omap_mbox_enable_irq(mbox, IRQ_RX);
 
        return 0;
@@ -586,13 +593,27 @@ static void omap_mbox_chan_shutdown(struct mbox_chan *chan)
        mutex_unlock(&mdev->cfg_lock);
 }
 
-static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
+static int omap_mbox_chan_send_noirq(struct omap_mbox *mbox, void *data)
 {
-       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
        int ret = -EBUSY;
 
-       if (!mbox)
-               return -EINVAL;
+       if (!mbox_fifo_full(mbox)) {
+               _omap_mbox_enable_irq(mbox, IRQ_RX);
+               mbox_fifo_write(mbox, (mbox_msg_t)data);
+               ret = 0;
+               _omap_mbox_disable_irq(mbox, IRQ_RX);
+
+               /* we must read and ack the interrupt directly from here */
+               mbox_fifo_read(mbox);
+               ack_mbox_irq(mbox, IRQ_RX);
+       }
+
+       return ret;
+}
+
+static int omap_mbox_chan_send(struct omap_mbox *mbox, void *data)
+{
+       int ret = -EBUSY;
 
        if (!mbox_fifo_full(mbox)) {
                mbox_fifo_write(mbox, (mbox_msg_t)data);
@@ -604,6 +625,22 @@ static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
        return ret;
 }
 
+static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
+{
+       struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+       int ret;
+
+       if (!mbox)
+               return -EINVAL;
+
+       if (mbox->send_no_irq)
+               ret = omap_mbox_chan_send_noirq(mbox, data);
+       else
+               ret = omap_mbox_chan_send(mbox, data);
+
+       return ret;
+}
+
 static const struct mbox_chan_ops omap_mbox_chan_ops = {
        .startup        = omap_mbox_chan_startup,
        .send_data      = omap_mbox_chan_send_data,
@@ -732,6 +769,9 @@ static int omap_mbox_probe(struct platform_device *pdev)
                        finfo->rx_usr = tmp[2];
 
                        finfo->name = child->name;
+
+                       if (of_find_property(child, "ti,mbox-send-noirq", NULL))
+                               finfo->send_no_irq = true;
                } else {
                        finfo->tx_id = info->tx_id;
                        finfo->rx_id = info->rx_id;
@@ -791,6 +831,7 @@ static int omap_mbox_probe(struct platform_device *pdev)
                fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->rx_usr);
                fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->rx_usr);
 
+               mbox->send_no_irq = finfo->send_no_irq;
                mbox->intr_type = intr_type;
 
                mbox->parent = mdev;
index 68885a82e7046456d95febb9381721931d2f3b2f..45d85aea9955404d0c4567f33863e0e3f500674f 100644 (file)
@@ -122,7 +122,7 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
         */
        chan = get_pcc_channel(subspace_id);
 
-       if (!chan || chan->cl) {
+       if (IS_ERR(chan) || chan->cl) {
                dev_err(dev, "Channel not found for idx: %d\n", subspace_id);
                return ERR_PTR(-EBUSY);
        }
index 7a228de95fd7e94fa61acb0758a53d8670770383..9eaf1d6e83023a2045063b8761a89b3983952f7c 100644 (file)
@@ -167,8 +167,6 @@ EXPORT_SYMBOL(closure_debug_destroy);
 
 static struct dentry *debug;
 
-#define work_data_bits(work) ((unsigned long *)(&(work)->data))
-
 static int debug_seq_show(struct seq_file *f, void *data)
 {
        struct closure *cl;
@@ -182,7 +180,7 @@ static int debug_seq_show(struct seq_file *f, void *data)
                           r & CLOSURE_REMAINING_MASK);
 
                seq_printf(f, "%s%s%s%s\n",
-                          test_bit(WORK_STRUCT_PENDING,
+                          test_bit(WORK_STRUCT_PENDING_BIT,
                                    work_data_bits(&cl->work)) ? "Q" : "",
                           r & CLOSURE_RUNNING  ? "R" : "",
                           r & CLOSURE_STACK    ? "S" : "",
index 001a7d7708cee1ad84a53839c8c687582331e649..6255513f54c7c2df29da53edb6a1dd2521b2dd4e 100644 (file)
@@ -25,8 +25,7 @@
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/seq_file.h>
-
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #include "intel-lpss.h"
 
index 464419b364408c084578cb3632c618bf52f62c7f..cc8645b5369d315afad0296ba4f5a5bd5a99ada8 100644 (file)
@@ -926,7 +926,7 @@ struct c2port_device *c2port_device_register(char *name,
 
        c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,
                                   "c2port%d", c2dev->id);
-       if (unlikely(IS_ERR(c2dev->dev))) {
+       if (IS_ERR(c2dev->dev)) {
                ret = PTR_ERR(c2dev->dev);
                goto error_device_create;
        }
index c8503006f17aaf63714cdd98f5e8fe9c80da8c78..08f62987cc37c4f02e7bf359806c802d9a601119 100644 (file)
@@ -48,6 +48,8 @@
  * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
  */
 
+#define pr_fmt(fmt)    "mtd: " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -55,9 +57,6 @@
 #include <linux/module.h>
 #include <linux/err.h>
 
-/* error message prefix */
-#define ERRP "mtd: "
-
 /* debug macro */
 #if 0
 #define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
@@ -115,9 +114,8 @@ static struct mtd_partition * newpart(char *s,
                s++;
        } else {
                size = memparse(s, &s);
-               if (size < PAGE_SIZE) {
-                       printk(KERN_ERR ERRP "partition size too small (%llx)\n",
-                              size);
+               if (!size) {
+                       pr_err("partition has size 0\n");
                        return ERR_PTR(-EINVAL);
                }
        }
@@ -142,7 +140,7 @@ static struct mtd_partition * newpart(char *s,
                name = ++s;
                p = strchr(name, delim);
                if (!p) {
-                       printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+                       pr_err("no closing %c found in partition name\n", delim);
                        return ERR_PTR(-EINVAL);
                }
                name_len = p - name;
@@ -170,7 +168,7 @@ static struct mtd_partition * newpart(char *s,
        /* test if more partitions are following */
        if (*s == ',') {
                if (size == SIZE_REMAINING) {
-                       printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+                       pr_err("no partitions allowed after a fill-up partition\n");
                        return ERR_PTR(-EINVAL);
                }
                /* more partitions follow, parse them */
@@ -237,7 +235,7 @@ static int mtdpart_setup_real(char *s)
                /* fetch <mtd-id> */
                p = strchr(s, ':');
                if (!p) {
-                       printk(KERN_ERR ERRP "no mtd-id\n");
+                       pr_err("no mtd-id\n");
                        return -EINVAL;
                }
                mtd_id_len = p - mtd_id;
@@ -289,7 +287,7 @@ static int mtdpart_setup_real(char *s)
 
                /* does another spec follow? */
                if (*s != ';') {
-                       printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+                       pr_err("bad character after partition (%c)\n", *s);
                        return -EINVAL;
                }
                s++;
@@ -343,17 +341,15 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                        part->parts[i].size = master->size - offset;
 
                if (offset + part->parts[i].size > master->size) {
-                       printk(KERN_WARNING ERRP
-                              "%s: partitioning exceeds flash size, truncating\n",
-                              part->mtd_id);
+                       pr_warn("%s: partitioning exceeds flash size, truncating\n",
+                               part->mtd_id);
                        part->parts[i].size = master->size - offset;
                }
                offset += part->parts[i].size;
 
                if (part->parts[i].size == 0) {
-                       printk(KERN_WARNING ERRP
-                              "%s: skipping zero sized partition\n",
-                              part->mtd_id);
+                       pr_warn("%s: skipping zero sized partition\n",
+                               part->mtd_id);
                        part->num_parts--;
                        memmove(&part->parts[i], &part->parts[i + 1],
                                sizeof(*part->parts) * (part->num_parts - i));
index 3d008a9410be9fae399c6ada3504c11fec8368aa..347bb83db8642a15320ed65771ca4e58d89da2b1 100644 (file)
@@ -237,13 +237,14 @@ static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
        return 0;
 }
 
-static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
+static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s,
+                                  struct device *dev)
 {
        struct mtd_info *mtd = &b47s->mtd;
 
        mtd->priv = b47s;
+       mtd->dev.parent = dev;
        mtd->name = "bcm47xxsflash";
-       mtd->owner = THIS_MODULE;
 
        mtd->type = MTD_NORFLASH;
        mtd->flags = MTD_CAP_NORFLASH;
@@ -300,7 +301,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
        b47s->blocksize = sflash->blocksize;
        b47s->numblocks = sflash->numblocks;
        b47s->size = sflash->size;
-       bcm47xxsflash_fill_mtd(b47s);
+       bcm47xxsflash_fill_mtd(b47s, &pdev->dev);
 
        err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
        if (err) {
index 5e67b4acde780e648669c8de753776a89f99fff8..c3a2695a442035ce269d0ca9bc79becf4450932b 100644 (file)
@@ -1620,20 +1620,30 @@ static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = {
 static int doc_register_sysfs(struct platform_device *pdev,
                              struct docg3_cascade *cascade)
 {
-       int ret = 0, floor, i = 0;
        struct device *dev = &pdev->dev;
+       int floor;
+       int ret;
+       int i;
 
-       for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS &&
-                    cascade->floors[floor]; floor++)
-               for (i = 0; !ret && i < 4; i++)
+       for (floor = 0;
+            floor < DOC_MAX_NBFLOORS && cascade->floors[floor];
+            floor++) {
+               for (i = 0; i < 4; i++) {
                        ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
-       if (!ret)
-               return 0;
+                       if (ret)
+                               goto remove_files;
+               }
+       }
+
+       return 0;
+
+remove_files:
        do {
                while (--i >= 0)
                        device_remove_file(dev, &doc_sys_attrs[floor][i]);
                i = 4;
        } while (--floor >= 0);
+
        return ret;
 }
 
@@ -1843,7 +1853,6 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
                mtd->erasesize /= 2;
        mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
        mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
-       mtd->owner = THIS_MODULE;
        mtd->_erase = doc_erase;
        mtd->_read = doc_read;
        mtd->_write = doc_write;
@@ -1885,6 +1894,7 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
        if (!mtd)
                goto nomem2;
        mtd->priv = docg3;
+       mtd->dev.parent = dev;
        bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1,
                                   8 * DOC_LAYOUT_PAGE_SIZE);
        docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL);
index fcf171a1325e1af7765c449a33d4c7df3fa26f81..fe9ceb7b5405adc029842ebc444e8c82e690ec89 100644 (file)
@@ -31,7 +31,6 @@
 struct m25p {
        struct spi_device       *spi;
        struct spi_nor          spi_nor;
-       struct mtd_info         mtd;
        u8                      command[MAX_CMD_SIZE];
 };
 
@@ -62,8 +61,7 @@ static int m25p_cmdsz(struct spi_nor *nor)
        return 1 + nor->addr_width;
 }
 
-static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int wr_en)
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
@@ -159,7 +157,7 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
        struct m25p *flash = nor->priv;
 
        dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
-               flash->mtd.erasesize / 1024, (u32)offset);
+               flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
 
        /* Set up command buffer. */
        flash->command[0] = nor->erase_opcode;
@@ -201,11 +199,10 @@ static int m25p_probe(struct spi_device *spi)
        nor->read_reg = m25p80_read_reg;
 
        nor->dev = &spi->dev;
-       nor->mtd = &flash->mtd;
+       nor->flash_node = spi->dev.of_node;
        nor->priv = flash;
 
        spi_set_drvdata(spi, flash);
-       flash->mtd.priv = nor;
        flash->spi = spi;
 
        if (spi->mode & SPI_RX_QUAD)
@@ -214,7 +211,7 @@ static int m25p_probe(struct spi_device *spi)
                mode = SPI_NOR_DUAL;
 
        if (data && data->name)
-               flash->mtd.name = data->name;
+               nor->mtd.name = data->name;
 
        /* For some (historical?) reason many platforms provide two different
         * names in flash_platform_data: "name" and "type". Quite often name is
@@ -232,7 +229,7 @@ static int m25p_probe(struct spi_device *spi)
 
        ppdata.of_node = spi->dev.of_node;
 
-       return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
+       return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
                        data ? data->parts : NULL,
                        data ? data->nr_parts : 0);
 }
@@ -243,7 +240,7 @@ static int m25p_remove(struct spi_device *spi)
        struct m25p     *flash = spi_get_drvdata(spi);
 
        /* Clean up MTD stuff. */
-       return mtd_device_unregister(&flash->mtd);
+       return mtd_device_unregister(&flash->spi_nor.mtd);
 }
 
 /*
index 70c16399e8bad28ef1fca2b5834aa38ea98370af..e4a88715a844952b73a62bd5427af89b46935cd4 100644 (file)
@@ -648,7 +648,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        device->size = nr_pages * pagesize;
        device->erasesize = pagesize;
        device->writesize = pagesize;
-       device->owner = THIS_MODULE;
        device->type = MTD_DATAFLASH;
        device->flags = MTD_WRITEABLE;
        device->_erase = dataflash_erase;
index 8e285089229c364ee29c6b4f7c90a872d6e7c693..627a9bc3767927a85d8a15a3eb1a74275673d251 100644 (file)
@@ -32,8 +32,29 @@ MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 // We could store these in the mtd structure, but we only support 1 device..
 static struct mtd_info *mtd_info;
 
+static int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       int ret = 0;
+
+       /* Start address must align on block boundary */
+       if (mtd_mod_by_eb(ofs, mtd)) {
+               pr_debug("%s: unaligned address\n", __func__);
+               ret = -EINVAL;
+       }
+
+       /* Length must align on block boundary */
+       if (mtd_mod_by_eb(len, mtd)) {
+               pr_debug("%s: length not block aligned\n", __func__);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
 static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
+       if (check_offs_len(mtd, instr->addr, instr->len))
+               return -EINVAL;
        memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
index 04b24d2b03f285ab10c98d742b2915e48b3e4189..64c7458344d4331e2e03e99034fbb0e051b24528 100644 (file)
@@ -854,6 +854,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
        else
                flash->mtd.name = flash_devices[flash_index].name;
 
+       flash->mtd.dev.parent = &pdev->dev;
        flash->mtd.type = MTD_NORFLASH;
        flash->mtd.writesize = 1;
        flash->mtd.flags = MTD_CAP_NORFLASH;
index 18febf74404d808597e0b1b737535e8a82b8369e..5b84d71efb3642f179b5128ae2d4c6c76a4cdc31 100644 (file)
@@ -374,9 +374,8 @@ static int sst25l_probe(struct spi_device *spi)
        data = dev_get_platdata(&spi->dev);
        if (data && data->name)
                flash->mtd.name = data->name;
-       else
-               flash->mtd.name = dev_name(&spi->dev);
 
+       flash->mtd.dev.parent   = &spi->dev;
        flash->mtd.type         = MTD_NORFLASH;
        flash->mtd.flags        = MTD_CAP_NORFLASH;
        flash->mtd.erasesize    = flash_info->erase_size;
index 063cec40d0aeda7ea10b9b7e9f3ac1db3b6ef31e..2342277c9bcb063f3c1c4691ecfe467cac04dfa8 100644 (file)
@@ -460,6 +460,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
 
        /* Populate mtd_info data structure */
        *mtd = (struct mtd_info) {
+               .dev            = { .parent = &pdev->dev },
                .name           = pdev->dev.init_name,
                .type           = MTD_RAM,
                .priv           = map,
index 2fb346091af2827b2ae1d238f511f641d00acde2..385305e66fd1c2af4d50f1984a58e7191832be21 100644 (file)
@@ -266,7 +266,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
                kfree(state);
                return -ENXIO;
        }
-
+       state->mtd->dev.parent = &pdev->dev;
 
        mtd_device_parse_register(state->mtd, part_probe_types, NULL,
                                  pdata->parts, pdata->nr_parts);
index 5ab71f0e1bcd6e3b4ae279aeded4e8c980bc9524..8bf79775e7c1abb8b5652008c48f6179029f79cd 100644 (file)
@@ -90,7 +90,7 @@ static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
        if (!p->info)
                return -ENODEV;
 
-       p->info->owner = THIS_MODULE;
+       p->info->dev.parent = &p->dev->dev;
 
        return 0;
 }
index b4430741024e728444b9e96426d4dbb6192d5669..e3180d5aa06a0fb4fd09e842d01939164373520f 100644 (file)
@@ -226,7 +226,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
                err = -ENXIO;
                goto Error;
        }
-       info->mtd->owner = THIS_MODULE;
+       info->mtd->dev.parent = &dev->dev;
 
        /* Use the fast version */
        info->map.write = ixp4xx_write16;
index e2f878216048eed8ac69e973d5da7e9f4e668147..93852054977ea52a52bea1031296184d754e2761 100644 (file)
@@ -160,7 +160,7 @@ ltq_mtd_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       ltq_mtd->mtd->owner = THIS_MODULE;
+       ltq_mtd->mtd->dev.parent = &pdev->dev;
 
        cfi = ltq_mtd->map->fldrv_priv;
        cfi->addr_unlock1 ^= 1;
index cadfbe05187316a93449d69a0fb6773720a3aa06..6dc97aa667dc553cc44033b34394374b3c8b36d1 100644 (file)
@@ -195,7 +195,7 @@ static int latch_addr_flash_probe(struct platform_device *dev)
                err = -ENODEV;
                goto iounmap;
        }
-       info->mtd->owner = THIS_MODULE;
+       info->mtd->dev.parent = &dev->dev;
 
        mtd_device_parse_register(info->mtd, NULL, NULL,
                                  latch_addr_data->parts,
index af747af5eee9f9917aa503393e14ddc422a4a531..3dad2111b7e331ee1d97f89530f57f8732a5d0b9 100644 (file)
@@ -700,6 +700,7 @@ static const struct pcmcia_device_id pcmciamtd_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
        PCMCIA_DEVICE_PROD_ID123("M-Systems", "M-SYS Flash Memory Card", "(c) M-Systems", 0x7ed2ad87, 0x675dc3fb, 0x7aef3965),
        PCMCIA_DEVICE_PROD_ID12("PRETEC", "  2MB SRAM CARD", 0xebf91155, 0x805360ca),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "  4MB SRAM CARD", 0xebf91155, 0x20b6bf17),
        PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
        PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
        PCMCIA_DEVICE_PROD_ID12("SMART Modular Technologies", " 4MB FLASH Card", 0x96fd8277, 0x737a5b05),
index 4305fd607015367cea988c9c8dcdbc21b1116d8d..cc2adbbcd60fe0ac0329de8893cf4b9670cac62d 100644 (file)
@@ -167,7 +167,6 @@ static int physmap_flash_probe(struct platform_device *dev)
                } else {
                        devices_found++;
                }
-               info->mtd[i]->owner = THIS_MODULE;
                info->mtd[i]->dev.parent = &dev->dev;
        }
 
index 3e614e9119d58414c0adfdec475629eaf5bb44d4..e46b4e9836668ed5e434e26bb963c2d87b2b7588 100644 (file)
@@ -290,7 +290,6 @@ static int of_flash_probe(struct platform_device *dev)
                } else {
                        info->list_size++;
                }
-               info->list[i].mtd->owner = THIS_MODULE;
                info->list[i].mtd->dev.parent = &dev->dev;
        }
 
index 4b65c08d15f6b7a11460136351e4e1497fce06f5..51572895c02cc42f8d3ad0d153625c8d3e7263ee 100644 (file)
@@ -210,7 +210,6 @@ static int platram_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
-       info->mtd->owner = THIS_MODULE;
        info->mtd->dev.parent = &pdev->dev;
 
        platram_setrw(info, PLATRAM_RW);
index 12fa75df50084dea86a41d991dee96e5ebd14096..7497090e990029fdf6b2161f4d2eb378abf2c540 100644 (file)
@@ -71,8 +71,8 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
                       info->map.name);
                return -ENOMEM;
        }
-       info->map.cached =
-               ioremap_cache(info->map.phys, info->map.size);
+       info->map.cached = memremap(info->map.phys, info->map.size,
+                       MEMREMAP_WB);
        if (!info->map.cached)
                printk(KERN_WARNING "Failed to ioremap cached %s\n",
                       info->map.name);
@@ -93,7 +93,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
                        iounmap(info->map.cached);
                return -EIO;
        }
-       info->mtd->owner = THIS_MODULE;
+       info->mtd->dev.parent = &pdev->dev;
 
        mtd_device_parse_register(info->mtd, probes, NULL, flash->parts,
                                  flash->nr_parts);
@@ -111,7 +111,7 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
        map_destroy(info->mtd);
        iounmap(info->map.virt);
        if (info->map.cached)
-               iounmap(info->map.cached);
+               memunmap(info->map.cached);
        kfree(info);
        return 0;
 }
index 5a7551aa2d8906a0e89ef4bf30465004c3d5c531..3a06ecfc55ff6baf9782cfc78118b2feff564744 100644 (file)
@@ -96,7 +96,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
                err = -ENXIO;
                goto err_out;
        }
-       info->mtd->owner = THIS_MODULE;
+       info->mtd->dev.parent = &dev->dev;
        err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
                                        pdata->nr_parts);
 
index 892ad6ac63f2936a12ecd52c256b07c5dbd395e1..142fc3d794637366cc4a4996b5e07f882d14b7a2 100644 (file)
@@ -117,7 +117,6 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r
                ret = -ENXIO;
                goto err;
        }
-       subdev->mtd->owner = THIS_MODULE;
 
        printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
                phys, (unsigned)(subdev->mtd->size >> 20),
@@ -234,6 +233,7 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
                if (info->mtd == NULL)
                        ret = -ENXIO;
        }
+       info->mtd->dev.parent = &pdev->dev;
 
        if (ret == 0)
                return info;
index 44dc965a2f7c0d10d2f55245568274a59db0a1ff..f4701182b558ecbf6ee714ea0fc24fb5d4730f3e 100644 (file)
@@ -192,8 +192,8 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
        if (!dev)
                return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
 
-       mutex_lock(&dev->lock);
        mutex_lock(&mtd_table_mutex);
+       mutex_lock(&dev->lock);
 
        if (dev->open)
                goto unlock;
@@ -217,8 +217,8 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
 
 unlock:
        dev->open++;
-       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
+       mutex_unlock(&mtd_table_mutex);
        blktrans_dev_put(dev);
        return ret;
 
@@ -228,8 +228,8 @@ error_release:
 error_put:
        module_put(dev->tr->owner);
        kref_put(&dev->ref, blktrans_dev_release);
-       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
+       mutex_unlock(&mtd_table_mutex);
        blktrans_dev_put(dev);
        return ret;
 }
@@ -241,8 +241,8 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
        if (!dev)
                return;
 
-       mutex_lock(&dev->lock);
        mutex_lock(&mtd_table_mutex);
+       mutex_lock(&dev->lock);
 
        if (--dev->open)
                goto unlock;
@@ -256,8 +256,8 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
                __put_mtd_device(dev->mtd);
        }
 unlock:
-       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
+       mutex_unlock(&mtd_table_mutex);
        blktrans_dev_put(dev);
 }
 
@@ -399,7 +399,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                snprintf(gd->disk_name, sizeof(gd->disk_name),
                         "%s%d", tr->name, new->devnum);
 
-       set_capacity(gd, (new->size * tr->blksize) >> 9);
+       set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
 
        /* Create the request queue */
        spin_lock_init(&new->queue_lock);
index 55fa27ecf4e15203f83808c87fc5cea8f18661b4..6d19835b80a952e098cfdfa8436971d5c68a593e 100644 (file)
@@ -498,21 +498,17 @@ static int shrink_ecclayout(const struct nand_ecclayout *from,
 }
 
 static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
-                          struct blkpg_ioctl_arg __user *arg)
+                              struct blkpg_ioctl_arg *arg)
 {
-       struct blkpg_ioctl_arg a;
        struct blkpg_partition p;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+       if (copy_from_user(&p, arg->data, sizeof(p)))
                return -EFAULT;
 
-       if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-               return -EFAULT;
-
-       switch (a.op) {
+       switch (arg->op) {
        case BLKPG_ADD_PARTITION:
 
                /* Only master mtd device must be used to add partitions */
@@ -966,8 +962,13 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 
        case BLKPG:
        {
-               ret = mtdchar_blkpg_ioctl(mtd,
-                     (struct blkpg_ioctl_arg __user *)arg);
+               struct blkpg_ioctl_arg __user *blk_arg = argp;
+               struct blkpg_ioctl_arg a;
+
+               if (copy_from_user(&a, blk_arg, sizeof(a)))
+                       ret = -EFAULT;
+               else
+                       ret = mtdchar_blkpg_ioctl(mtd, &a);
                break;
        }
 
@@ -1046,6 +1047,29 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd,
                                &buf_user->start);
                break;
        }
+
+       case BLKPG:
+       {
+               /* Convert from blkpg_compat_ioctl_arg to blkpg_ioctl_arg */
+               struct blkpg_compat_ioctl_arg __user *uarg = argp;
+               struct blkpg_compat_ioctl_arg compat_arg;
+               struct blkpg_ioctl_arg a;
+
+               if (copy_from_user(&compat_arg, uarg, sizeof(compat_arg))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               memset(&a, 0, sizeof(a));
+               a.op = compat_arg.op;
+               a.flags = compat_arg.flags;
+               a.datalen = compat_arg.datalen;
+               a.data = compat_ptr(compat_arg.data);
+
+               ret = mtdchar_blkpg_ioctl(mtd, &a);
+               break;
+       }
+
        default:
                ret = mtdchar_ioctl(file, cmd, (unsigned long)argp);
        }
index 2dfb291a47c6da6e64caa1788f1329305658b9c5..95c13b2ffa799e59f453e8a95813171cd56a13fc 100644 (file)
@@ -387,6 +387,14 @@ int add_mtd_device(struct mtd_info *mtd)
        struct mtd_notifier *not;
        int i, error;
 
+       /*
+        * May occur, for instance, on buggy drivers which call
+        * mtd_device_parse_register() multiple times on the same master MTD,
+        * especially with CONFIG_MTD_PARTITIONED_MASTER=y.
+        */
+       if (WARN_ONCE(mtd->backing_dev_info, "MTD already registered\n"))
+               return -EEXIST;
+
        mtd->backing_dev_info = &mtd_bdi;
 
        BUG_ON(mtd->writesize == 0);
@@ -418,6 +426,15 @@ int add_mtd_device(struct mtd_info *mtd)
        mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
        mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
 
+       if (mtd->dev.parent) {
+               if (!mtd->owner && mtd->dev.parent->driver)
+                       mtd->owner = mtd->dev.parent->driver->owner;
+               if (!mtd->name)
+                       mtd->name = dev_name(mtd->dev.parent);
+       } else {
+               pr_debug("mtd device won't show a device symlink in sysfs\n");
+       }
+
        /* Some chips always power up locked. Unlock them now */
        if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
                error = mtd_unlock(mtd, 0, mtd->size);
@@ -430,7 +447,7 @@ int add_mtd_device(struct mtd_info *mtd)
        }
 
        /* Caller should have set dev.parent to match the
-        * physical device.
+        * physical device, if appropriate.
         */
        mtd->dev.type = &mtd_devtype;
        mtd->dev.class = &mtd_class;
@@ -579,9 +596,17 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
                else
                        ret = nr_parts;
        }
+       /* Didn't come up with either parsed OR fallback partitions */
+       if (ret < 0) {
+               pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
+                       ret);
+               /* Don't abort on errors; we can still use unpartitioned MTD */
+               ret = 0;
+       }
 
-       if (ret >= 0)
-               ret = mtd_add_device_partitions(mtd, real_parts, ret);
+       ret = mtd_add_device_partitions(mtd, real_parts, ret);
+       if (ret)
+               goto out;
 
        /*
         * FIXME: some drivers unfortunately call this function more than once.
@@ -591,11 +616,14 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
         * does cause problems with parse_mtd_partitions() above (e.g.,
         * cmdlineparts will register partitions more than once).
         */
+       WARN_ONCE(mtd->_reboot && mtd->reboot_notifier.notifier_call,
+                 "MTD already registered\n");
        if (mtd->_reboot && !mtd->reboot_notifier.notifier_call) {
                mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
                register_reboot_notifier(&mtd->reboot_notifier);
        }
 
+out:
        kfree(real_parts);
        return ret;
 }
@@ -1300,6 +1328,7 @@ static void __exit cleanup_mtd(void)
                remove_proc_entry("mtd", NULL);
        class_unregister(&mtd_class);
        bdi_destroy(&mtd_bdi);
+       idr_destroy(&mtd_idr);
 }
 
 module_init(init_mtd);
index cafdb8855a794f93f2adf56ca917fcb7a283e9df..f8ba153f63bfebc5750a6d31b109dbc9d574cef8 100644 (file)
@@ -664,8 +664,10 @@ int add_mtd_partitions(struct mtd_info *master,
 
        for (i = 0; i < nbparts; i++) {
                slave = allocate_partition(master, parts + i, i, cur_offset);
-               if (IS_ERR(slave))
+               if (IS_ERR(slave)) {
+                       del_mtd_partitions(master);
                        return PTR_ERR(slave);
+               }
 
                mutex_lock(&mtd_partitions_mutex);
                list_add(&slave->list, &mtd_partitions);
@@ -753,26 +755,37 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
                         struct mtd_part_parser_data *data)
 {
        struct mtd_part_parser *parser;
-       int ret = 0;
+       int ret, err = 0;
 
        if (!types)
                types = default_mtd_part_types;
 
-       for ( ; ret <= 0 && *types; types++) {
+       for ( ; *types; types++) {
+               pr_debug("%s: parsing partitions %s\n", master->name, *types);
                parser = get_partition_parser(*types);
                if (!parser && !request_module("%s", *types))
                        parser = get_partition_parser(*types);
+               pr_debug("%s: got parser %s\n", master->name,
+                        parser ? parser->name : NULL);
                if (!parser)
                        continue;
                ret = (*parser->parse_fn)(master, pparts, data);
+               pr_debug("%s: parser %s: %i\n",
+                        master->name, parser->name, ret);
                put_partition_parser(parser);
                if (ret > 0) {
                        printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
                               ret, parser->name, master->name);
-                       break;
+                       return ret;
                }
+               /*
+                * Stash the first error we see; only report it if no parser
+                * succeeds
+                */
+               if (ret < 0 && !err)
+                       err = ret;
        }
-       return ret;
+       return err;
 }
 
 int mtd_is_partition(const struct mtd_info *mtd)
index 3324281d1f53f99bd297c4bf9e56b341a0a1932c..289664089cf32ce9770baefba951e089f0681a11 100644 (file)
@@ -393,7 +393,7 @@ config MTD_NAND_GPMI_NAND
 
 config MTD_NAND_BRCMNAND
        tristate "Broadcom STB NAND controller"
-       depends on ARM || MIPS
+       depends on ARM || ARM64 || MIPS
        help
          Enables the Broadcom NAND controller driver. The controller was
          originally designed for Set-Top Box but is used on various BCM7xxx,
@@ -460,6 +460,17 @@ config MTD_NAND_MPC5121_NFC
          This enables the driver for the NAND flash controller on the
          MPC5121 SoC.
 
+config MTD_NAND_VF610_NFC
+       tristate "Support for Freescale NFC for VF610/MPC5125"
+       depends on (SOC_VF610 || COMPILE_TEST)
+       help
+         Enables support for NAND Flash Controller on some Freescale
+         processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+         The driver supports a maximum 2k page size. With 2k pages and
+         64 bytes or more of OOB, hardware ECC with up to 32-bit error
+         correction is supported. Hardware ECC is only enabled through
+         device tree.
+
 config MTD_NAND_MXC
        tristate "MXC NAND support"
        depends on ARCH_MXC
index 075a027632b5c88ac73d2d1fd7eed49569f713c3..2c7f014b349e56c50b6fd2cf109bd5ed0f9f7eb7 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_MTD_NAND_SOCRATES)               += socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)       += txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_NUC900)          += nuc900_nand.o
 obj-$(CONFIG_MTD_NAND_MPC5121_NFC)     += mpc5121_nfc.o
+obj-$(CONFIG_MTD_NAND_VF610_NFC)       += vf610_nfc.o
 obj-$(CONFIG_MTD_NAND_RICOH)           += r852.o
 obj-$(CONFIG_MTD_NAND_JZ4740)          += jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)       += gpmi-nand/
index 46010bd895b152598d44b9a47004c42de374a678..583cdd9bb9710b0168f9b16892906e2a6535666f 100644 (file)
@@ -954,7 +954,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 }
 
 static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf, int oob_required)
+               struct nand_chip *chip, const uint8_t *buf, int oob_required,
+               int page)
 {
        struct atmel_nand_host *host = chip->priv;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -2005,7 +2006,8 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (likely(!raw))
                /* Need to write ecc into oob */
-               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required,
+                                             page);
 
        if (status < 0)
                return status;
@@ -2126,7 +2128,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
 
        nand_chip->priv = host;         /* link the private data structures */
        mtd->priv = nand_chip;
-       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
 
        /* Set address of NAND IO lines */
        nand_chip->IO_ADDR_R = host->io_base;
index c0c3be180012f6fe41e61c4a4f510af6872bc74d..08a130f63faff4b8b8bd22f0967ccc443d6455e5 100644 (file)
@@ -439,7 +439,7 @@ static int au1550nd_probe(struct platform_device *pdev)
 
        this = &ctx->chip;
        ctx->info.priv = this;
-       ctx->info.owner = THIS_MODULE;
+       ctx->info.dev.parent = &pdev->dev;
 
        /* figure out which CS# r->start belongs to */
        cs = find_nand_cs(r->start);
index 461577cfb5bc64d2d6ccebeea6d79cc3fff11b34..9ba0c0f2cd9bbe1b729cb9afba77ab531fe3703c 100644 (file)
@@ -34,7 +34,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        b47n->nand_chip.priv = b47n;
-       b47n->mtd.owner = THIS_MODULE;
+       b47n->mtd.dev.parent = &pdev->dev;
        b47n->mtd.priv = &b47n->nand_chip; /* Required */
        b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
 
index 4d8d4ba4b9c1068d045225b54ec657eba0b96121..61bd2160717ce425dc6b7234b3e8ea07c06f1387 100644 (file)
@@ -566,7 +566,8 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip
 }
 
 static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf, int oob_required)
+               struct nand_chip *chip, const uint8_t *buf, int oob_required,
+               int page)
 {
        bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
        bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -782,7 +783,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
        /* initialise mtd info data struct */
        mtd             = &info->mtd;
        mtd->priv       = chip;
-       mtd->owner      = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
 
        /* initialise the hardware */
        err = bf5xx_nand_hw_init(info);
index 3f4c44c24e14e88a999fbeb42ca40e2bb54d8efe..59444b3a697d12ebf23033b8ecdfb224bc98da37 100644 (file)
@@ -22,7 +22,8 @@
 
 #include "brcmnand.h"
 
-struct bcm63138_nand_soc_priv {
+struct bcm63138_nand_soc {
+       struct brcmnand_soc soc;
        void __iomem *base;
 };
 
@@ -35,7 +36,8 @@ enum {
 
 static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
 {
-       struct bcm63138_nand_soc_priv *priv = soc->priv;
+       struct bcm63138_nand_soc *priv =
+                       container_of(soc, struct bcm63138_nand_soc, soc);
        void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
        u32 val = brcmnand_readl(mmio);
 
@@ -49,7 +51,8 @@ static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
 
 static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
 {
-       struct bcm63138_nand_soc_priv *priv = soc->priv;
+       struct bcm63138_nand_soc *priv =
+                       container_of(soc, struct bcm63138_nand_soc, soc);
        void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
        u32 val = brcmnand_readl(mmio);
 
@@ -64,25 +67,20 @@ static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
 static int bcm63138_nand_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct bcm63138_nand_soc_priv *priv;
+       struct bcm63138_nand_soc *priv;
        struct brcmnand_soc *soc;
        struct resource *res;
 
-       soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
-       if (!soc)
-               return -ENOMEM;
-
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
+       soc = &priv->soc;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
        priv->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       soc->pdev = pdev;
-       soc->priv = priv;
        soc->ctlrdy_ack = bcm63138_nand_intc_ack;
        soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
 
index fddb795eeb710c0580fa22af3d12436039fb18ea..12c6190c6e338be6a25c878db9e5870bf3a02fef 100644 (file)
@@ -344,6 +344,28 @@ static const u8 brcmnand_cs_offsets_cs0[] = {
        [BRCMNAND_CS_TIMING2]           = 0x14,
 };
 
+/*
+ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
+ * one config register, but once the bitfields overflowed, newer controllers
+ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
+ */
+enum {
+       CFG_BLK_ADR_BYTES_SHIFT         = 8,
+       CFG_COL_ADR_BYTES_SHIFT         = 12,
+       CFG_FUL_ADR_BYTES_SHIFT         = 16,
+       CFG_BUS_WIDTH_SHIFT             = 23,
+       CFG_BUS_WIDTH                   = BIT(CFG_BUS_WIDTH_SHIFT),
+       CFG_DEVICE_SIZE_SHIFT           = 24,
+
+       /* Only for pre-v7.1 (with no CFG_EXT register) */
+       CFG_PAGE_SIZE_SHIFT             = 20,
+       CFG_BLK_SIZE_SHIFT              = 28,
+
+       /* Only for v7.1+ (with CFG_EXT register) */
+       CFG_EXT_PAGE_SIZE_SHIFT         = 0,
+       CFG_EXT_BLK_SIZE_SHIFT          = 4,
+};
+
 /* BRCMNAND_INTFC_STATUS */
 enum {
        INTFC_FLASH_STATUS              = GENMASK(7, 0),
@@ -1544,9 +1566,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
 
        dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
 
-       if (unlikely((u32)buf & 0x03)) {
+       if (unlikely((unsigned long)buf & 0x03)) {
                dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
-               buf = (u32 *)((u32)buf & ~0x03);
+               buf = (u32 *)((unsigned long)buf & ~0x03);
        }
 
        brcmnand_wp(mtd, 0);
@@ -1606,7 +1628,7 @@ out:
 }
 
 static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required)
+                              const uint8_t *buf, int oob_required, int page)
 {
        struct brcmnand_host *host = chip->priv;
        void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1617,7 +1639,7 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int brcmnand_write_page_raw(struct mtd_info *mtd,
                                   struct nand_chip *chip, const uint8_t *buf,
-                                  int oob_required)
+                                  int oob_required, int page)
 {
        struct brcmnand_host *host = chip->priv;
        void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1720,17 +1742,19 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
        }
        device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
 
-       tmp = (cfg->blk_adr_bytes << 8) |
-               (cfg->col_adr_bytes << 12) |
-               (cfg->ful_adr_bytes << 16) |
-               (!!(cfg->device_width == 16) << 23) |
-               (device_size << 24);
+       tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
+               (cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
+               (cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
+               (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
+               (device_size << CFG_DEVICE_SIZE_SHIFT);
        if (cfg_offs == cfg_ext_offs) {
-               tmp |= (page_size << 20) | (block_size << 28);
+               tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
+                      (block_size << CFG_BLK_SIZE_SHIFT);
                nand_writereg(ctrl, cfg_offs, tmp);
        } else {
                nand_writereg(ctrl, cfg_offs, tmp);
-               tmp = page_size | (block_size << 4);
+               tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
+                     (block_size << CFG_EXT_BLK_SIZE_SHIFT);
                nand_writereg(ctrl, cfg_ext_offs, tmp);
        }
 
@@ -1792,7 +1816,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 
        memset(cfg, 0, sizeof(*cfg));
 
-       ret = of_property_read_u32(chip->dn, "brcm,nand-oob-sector-size",
+       ret = of_property_read_u32(chip->flash_node,
+                                  "brcm,nand-oob-sector-size",
                                   &oob_sector);
        if (ret) {
                /* Use detected size */
@@ -1888,6 +1913,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
        struct mtd_info *mtd;
        struct nand_chip *chip;
        int ret;
+       u16 cfg_offs;
        struct mtd_part_parser_data ppdata = { .of_node = dn };
 
        ret = of_property_read_u32(dn, "reg", &host->cs);
@@ -1899,7 +1925,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
        mtd = &host->mtd;
        chip = &host->chip;
 
-       chip->dn = dn;
+       chip->flash_node = dn;
        chip->priv = host;
        mtd->priv = chip;
        mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
@@ -1930,6 +1956,15 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
 
        chip->controller = &ctrl->controller;
 
+       /*
+        * The bootloader might have configured 16bit mode but
+        * NAND READID command only works in 8bit mode. We force
+        * 8bit mode here to ensure that NAND READID commands works.
+        */
+       cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+       nand_writereg(ctrl, cfg_offs,
+                     nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
+
        if (nand_scan_ident(mtd, 1, NULL))
                return -ENXIO;
 
index 169f99e38a2666450d84e8209559d7bf913aa1a4..ef5eabba88e58ac3866521cd8ef2f6f67ae6b42c 100644 (file)
@@ -21,8 +21,6 @@ struct platform_device;
 struct dev_pm_ops;
 
 struct brcmnand_soc {
-       struct platform_device *pdev;
-       void *priv;
        bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
        void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
        void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
index 683495c746204232ebfadc5f72ebe90c62bfd6a3..585596c549b296b9a38114d988f7aa589a265cfb 100644 (file)
@@ -22,7 +22,9 @@
 
 #include "brcmnand.h"
 
-struct iproc_nand_soc_priv {
+struct iproc_nand_soc {
+       struct brcmnand_soc soc;
+
        void __iomem *idm_base;
        void __iomem *ext_base;
        spinlock_t idm_lock;
@@ -37,7 +39,8 @@ struct iproc_nand_soc_priv {
 
 static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
 {
-       struct iproc_nand_soc_priv *priv = soc->priv;
+       struct iproc_nand_soc *priv =
+                       container_of(soc, struct iproc_nand_soc, soc);
        void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
        u32 val = brcmnand_readl(mmio);
 
@@ -51,7 +54,8 @@ static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
 
 static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
 {
-       struct iproc_nand_soc_priv *priv = soc->priv;
+       struct iproc_nand_soc *priv =
+                       container_of(soc, struct iproc_nand_soc, soc);
        void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
        u32 val;
        unsigned long flags;
@@ -72,7 +76,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
 
 static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
 {
-       struct iproc_nand_soc_priv *priv = soc->priv;
+       struct iproc_nand_soc *priv =
+                       container_of(soc, struct iproc_nand_soc, soc);
        void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
        u32 val;
        unsigned long flags;
@@ -94,17 +99,14 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
 static int iproc_nand_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct iproc_nand_soc_priv *priv;
+       struct iproc_nand_soc *priv;
        struct brcmnand_soc *soc;
        struct resource *res;
 
-       soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
-       if (!soc)
-               return -ENOMEM;
-
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
+       soc = &priv->soc;
 
        spin_lock_init(&priv->idm_lock);
 
@@ -118,8 +120,6 @@ static int iproc_nand_probe(struct platform_device *pdev)
        if (IS_ERR(priv->ext_base))
                return PTR_ERR(priv->ext_base);
 
-       soc->pdev = pdev;
-       soc->priv = priv;
        soc->ctlrdy_ack = iproc_nand_intc_ack;
        soc->ctlrdy_set_enabled = iproc_nand_intc_set;
        soc->prepare_data_bus = iproc_nand_apb_access;
index 9a0f45f1d932d987b4ae11c138d7362a6414dc61..9de78d2a2eb189bcf9fd2a630d077d0a34515016 100644 (file)
@@ -516,7 +516,8 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
 
 static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
                                          struct nand_chip *chip,
-                                         const uint8_t *buf, int oob_required)
+                                         const uint8_t *buf, int oob_required,
+                                         int page)
 {
        struct cafe_priv *cafe = mtd->priv;
 
@@ -604,7 +605,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        mtd->dev.parent = &pdev->dev;
        mtd->priv = cafe;
-       mtd->owner = THIS_MODULE;
 
        cafe->pdev = pdev;
        cafe->mmio = pci_iomap(pdev, 0, 0);
index b90801302df4e29a71bea76752af877b5c078bb0..c72313d66cf6a0d3034ba82d519a3bd315d21c59 100644 (file)
@@ -683,9 +683,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
        info->vaddr             = vaddr;
 
        info->mtd.priv          = &info->chip;
-       info->mtd.name          = dev_name(&pdev->dev);
-       info->mtd.owner         = THIS_MODULE;
-
        info->mtd.dev.parent    = &pdev->dev;
 
        info->chip.IO_ADDR_R    = vaddr;
index 870c7fc0f759dc515539c170f2befeae2d2be872..67eb2be0db87be99464c2b1db58ce2a66433fb28 100644 (file)
@@ -458,8 +458,17 @@ static void find_valid_banks(struct denali_nand_info *denali)
 static void detect_max_banks(struct denali_nand_info *denali)
 {
        uint32_t features = ioread32(denali->flash_reg + FEATURES);
+       /*
+        * Read the revision register, so we can calculate the max_banks
+        * properly: the encoding changed from rev 5.0 to 5.1
+        */
+       u32 revision = MAKE_COMPARABLE_REVISION(
+                               ioread32(denali->flash_reg + REVISION));
 
-       denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+       if (revision < REVISION_5_1)
+               denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+       else
+               denali->max_banks = 1 << (features & FEATURES__N_BANKS);
 }
 
 static void detect_partition_feature(struct denali_nand_info *denali)
@@ -1105,7 +1114,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
  * by write_page above.
  */
 static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required)
+                               const uint8_t *buf, int oob_required, int page)
 {
        /*
         * for regular page writes, we let HW handle all the ECC
@@ -1120,7 +1129,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
  * write_page() function above.
  */
 static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                       const uint8_t *buf, int oob_required)
+                                const uint8_t *buf, int oob_required,
+                                int page)
 {
        /*
         * for raw page writes, we want to disable ECC and simply write
@@ -1304,7 +1314,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
                 */
                addr = MODE_11 | BANK(denali->flash_bank);
                index_addr(denali, addr | 0, 0x90);
-               index_addr(denali, addr | 1, 0);
+               index_addr(denali, addr | 1, col);
                for (i = 0; i < 8; i++) {
                        index_addr_read_data(denali, addr | 2, &id);
                        write_byte_to_buf(denali, id);
@@ -1454,7 +1464,6 @@ int denali_init(struct denali_nand_info *denali)
        /* now that our ISR is registered, we can enable interrupts */
        denali_set_intr_modes(denali, true);
        denali->mtd.name = "denali-nand";
-       denali->mtd.owner = THIS_MODULE;
        denali->mtd.priv = &denali->nand;
 
        /* register the driver with the NAND core subsystem */
index 145bf88930e82e24a6e9cd43fbd1a2cf81a60e0e..4b12cd302819ac21479ef84d5cee3237f7514834 100644 (file)
 
 #define REVISION                               0x370
 #define     REVISION__VALUE                            0xffff
+#define MAKE_COMPARABLE_REVISION(x)            swab16((x) & REVISION__VALUE)
+#define REVISION_5_1                           0x00000501
 
 #define ONFI_DEVICE_FEATURES                   0x380
 #define     ONFI_DEVICE_FEATURES__VALUE                        0x003f
index e5d7bcaafa7d165b784827a5e763476e63cc11a4..408cf69b854b97f9a55529c4dd4cdaa05e04ac86 100644 (file)
@@ -977,13 +977,13 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
 }
 
 static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
-                                const uint8_t *buf, int oob_required)
+                               const uint8_t *buf, int oob_required, int page)
 {
        return write_page(mtd, nand, buf, false);
 }
 
 static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
-                            const uint8_t *buf, int oob_required)
+                            const uint8_t *buf, int oob_required, int page)
 {
        return write_page(mtd, nand, buf, true);
 }
@@ -1113,7 +1113,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
        /* write first page of block */
        write_page_prologue(mtd, g4_addr);
-       docg4_write_page(mtd, nand, buf, 1);
+       docg4_write_page(mtd, nand, buf, 1, page);
        ret = pageprog(mtd);
 
        kfree(buf);
@@ -1316,7 +1316,7 @@ static int __init probe_docg4(struct platform_device *pdev)
        doc = (struct docg4_priv *) (nand + 1);
        mtd->priv = nand;
        nand->priv = doc;
-       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
        doc->virtadr = virtadr;
        doc->dev = dev;
 
index 04b22fd3732dfad5bc567c199bf2828a833abeee..dcb1f7f4873f39d8a38689af1467aa2b9b29c1f4 100644 (file)
@@ -715,7 +715,7 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
  * waitfunc.
  */
 static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required)
+                               const uint8_t *buf, int oob_required, int page)
 {
        fsl_elbc_write_buf(mtd, buf, mtd->writesize);
        fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -728,7 +728,7 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
  */
 static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
                                uint32_t offset, uint32_t data_len,
-                               const uint8_t *buf, int oob_required)
+                               const uint8_t *buf, int oob_required, int page)
 {
        fsl_elbc_write_buf(mtd, buf, mtd->writesize);
        fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -747,7 +747,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 
        /* Fill in fsl_elbc_mtd structure */
        priv->mtd.priv = chip;
-       priv->mtd.owner = THIS_MODULE;
+       priv->mtd.dev.parent = priv->dev;
 
        /* set timeout to maximum */
        priv->fmr = 15 << FMR_CWTO_SHIFT;
@@ -946,6 +946,7 @@ static const struct of_device_id fsl_elbc_nand_match[] = {
        { .compatible = "fsl,elbc-fcm-nand", },
        {}
 };
+MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
 
 static struct platform_driver fsl_elbc_nand_driver = {
        .driver = {
index a4e27e8911531e005046dab0af50977393cad899..7f4ac8c190016df2ebd291bd296046456542b106 100644 (file)
@@ -772,7 +772,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
  * waitfunc.
  */
 static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required)
+                              const uint8_t *buf, int oob_required, int page)
 {
        fsl_ifc_write_buf(mtd, buf, mtd->writesize);
        fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -882,7 +882,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        /* Fill in fsl_ifc_mtd structure */
        priv->mtd.priv = chip;
-       priv->mtd.owner = THIS_MODULE;
+       priv->mtd.dev.parent = priv->dev;
 
        /* fill in nand_chip structure */
        /* set up function call table */
@@ -1163,6 +1163,7 @@ static const struct of_device_id fsl_ifc_nand_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
 
 static struct platform_driver fsl_ifc_nand_driver = {
        .driver = {
index 72755d7ec25d750a90a9b933a60fb8aa74eb6326..d326369980c4811b780d864c46a1f737f305edac 100644 (file)
@@ -176,7 +176,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
                fun->chip.dev_ready = fun_chip_ready;
 
        fun->mtd.priv = &fun->chip;
-       fun->mtd.owner = THIS_MODULE;
+       fun->mtd.dev.parent = fun->dev;
 
        flash_np = of_get_next_child(upm_np, NULL);
        if (!flash_np)
index 793872f180657e65e7d82237853b511dd72e82b3..07af3dc7a4d2d9e82650af800a6aa4446d10a7a0 100644 (file)
@@ -348,7 +348,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
                break;
 
        default:
-               BUG();
+               dev_err(host->dev, "unsupported chip-select %d\n", chipnr);
        }
 }
 
@@ -960,7 +960,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        host->data_va = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->data_va))
                return PTR_ERR(host->data_va);
-       
+
        host->data_pa = (dma_addr_t)res->start;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
@@ -1017,18 +1017,23 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        mtd->priv = nand;
        nand->priv = host;
 
-       host->mtd.owner = THIS_MODULE;
+       host->mtd.dev.parent = &pdev->dev;
        nand->IO_ADDR_R = host->data_va;
        nand->IO_ADDR_W = host->data_va;
        nand->cmd_ctrl = fsmc_cmd_ctrl;
        nand->chip_delay = 30;
 
+       /*
+        * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
+        * can overwrite this value if the DT provides a different value.
+        */
        nand->ecc.mode = NAND_ECC_HW;
        nand->ecc.hwctl = fsmc_enable_hwecc;
        nand->ecc.size = 512;
        nand->options = pdata->options;
        nand->select_chip = fsmc_select_chip;
        nand->badblockbits = 7;
+       nand->flash_node = np;
 
        if (pdata->width == FSMC_NAND_BW16)
                nand->options |= NAND_BUSWIDTH_16;
@@ -1070,11 +1075,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                nand->ecc.correct = fsmc_bch8_correct_data;
                nand->ecc.bytes = 13;
                nand->ecc.strength = 8;
-       } else {
-               nand->ecc.calculate = fsmc_read_hwecc_ecc1;
-               nand->ecc.correct = nand_correct_data;
-               nand->ecc.bytes = 3;
-               nand->ecc.strength = 1;
        }
 
        /*
@@ -1111,23 +1111,50 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                default:
                        dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
                                 mtd->oobsize);
-                       BUG();
+                       ret = -EINVAL;
+                       goto err_probe;
                }
        } else {
-               switch (host->mtd.oobsize) {
-               case 16:
-                       nand->ecc.layout = &fsmc_ecc1_16_layout;
-                       break;
-               case 64:
-                       nand->ecc.layout = &fsmc_ecc1_64_layout;
+               switch (nand->ecc.mode) {
+               case NAND_ECC_HW:
+                       dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
+                       nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+                       nand->ecc.correct = nand_correct_data;
+                       nand->ecc.bytes = 3;
+                       nand->ecc.strength = 1;
                        break;
-               case 128:
-                       nand->ecc.layout = &fsmc_ecc1_128_layout;
+
+               case NAND_ECC_SOFT_BCH:
+                       dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
                        break;
+
                default:
-                       dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
-                                mtd->oobsize);
-                       BUG();
+                       dev_err(&pdev->dev, "Unsupported ECC mode!\n");
+                       goto err_probe;
+               }
+
+               /*
+                * Don't set layout for BCH4 SW ECC. This will be
+                * generated later in nand_bch_init() later.
+                */
+               if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
+                       switch (host->mtd.oobsize) {
+                       case 16:
+                               nand->ecc.layout = &fsmc_ecc1_16_layout;
+                               break;
+                       case 64:
+                               nand->ecc.layout = &fsmc_ecc1_64_layout;
+                               break;
+                       case 128:
+                               nand->ecc.layout = &fsmc_ecc1_128_layout;
+                               break;
+                       default:
+                               dev_warn(&pdev->dev,
+                                        "No oob scheme defined for oobsize %d\n",
+                                        mtd->oobsize);
+                               ret = -EINVAL;
+                               goto err_probe;
+                       }
                }
        }
 
index 73c4048c3a567047401f99bd87b0024d1b911c21..9ab97f934c375c2561b90c5799b45cdf8cf24f4a 100644 (file)
@@ -275,7 +275,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
        chip->cmd_ctrl          = gpio_nand_cmd_ctrl;
 
        gpiomtd->mtd_info.priv  = chip;
-       gpiomtd->mtd_info.owner = THIS_MODULE;
+       gpiomtd->mtd_info.dev.parent = &pdev->dev;
 
        platform_set_drvdata(pdev, gpiomtd);
 
index 1b8f3500e6d22613b7046e71af5ddb5c64717f65..2064adac1d1778871bb647e6678187e5a5de6da1 100644 (file)
@@ -1160,7 +1160,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required)
+                               const uint8_t *buf, int oob_required, int page)
 {
        struct gpmi_nand_data *this = chip->priv;
        struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -1446,7 +1446,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
 static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
                                   struct nand_chip *chip,
                                   const uint8_t *buf,
-                                  int oob_required)
+                                  int oob_required, int page)
 {
        struct gpmi_nand_data *this = chip->priv;
        struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -1533,7 +1533,7 @@ static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
 {
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
 
-       return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1);
+       return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
 }
 
 static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
@@ -1717,7 +1717,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
                /* Write the first page of the current stride. */
                dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
                chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-               chip->ecc.write_page_raw(mtd, chip, buffer, 0);
+               chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
                chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
                /* Wait for the write to finish. */
@@ -1897,7 +1897,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        /* init the MTD data structures */
        mtd->priv               = chip;
        mtd->name               = "gpmi-nand";
-       mtd->owner              = THIS_MODULE;
+       mtd->dev.parent         = this->dev;
 
        /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
        chip->priv              = this;
index 8dcc7b8fee40631680153d6fb7ca893546b1233f..0cb2e886937d6c1e1da9e7fe2b8919949bdcabee 100644 (file)
@@ -590,7 +590,8 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf, int oob_required)
+               struct nand_chip *chip, const uint8_t *buf, int oob_required,
+               int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
@@ -737,7 +738,6 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        }
 
        mtd->priv               = chip;
-       mtd->owner              = THIS_MODULE;
        mtd->name               = "hisi_nand";
        mtd->dev.parent         = &pdev->dev;
 
index ebf2cce04cba14a3caa3baf9d503aa17a730e969..dc4e8446f1ff10b55acf6c40a4cb0ac662cf2b06 100644 (file)
@@ -434,7 +434,7 @@ static int jz_nand_probe(struct platform_device *pdev)
        mtd             = &nand->mtd;
        chip            = &nand->chip;
        mtd->priv       = chip;
-       mtd->owner      = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
        mtd->name       = "jz4740-nand";
 
        chip->ecc.hwctl         = jz_nand_hwctl;
index 79c3b7801e1fc3d057b6b61598ecb09486dc7146..3475109784840e265633b6db10e0e594602e888c 100644 (file)
@@ -495,7 +495,8 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
                                       struct nand_chip *chip,
-                                      const uint8_t *buf, int oob_required)
+                                      const uint8_t *buf, int oob_required,
+                                      int page)
 {
        struct lpc32xx_nand_host *host = chip->priv;
        const uint8_t *oobbuf = chip->oob_poi;
@@ -682,7 +683,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        nand_chip->priv = host;         /* link the private data structures */
        mtd->priv = nand_chip;
-       mtd->owner = THIS_MODULE;
        mtd->dev.parent = &pdev->dev;
 
        /* Get NAND clock */
@@ -692,7 +692,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
                res = -ENOENT;
                goto err_exit1;
        }
-       clk_enable(host->clk);
+       clk_prepare_enable(host->clk);
 
        nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
        nand_chip->dev_ready = lpc32xx_nand_device_ready;
@@ -800,7 +800,7 @@ err_exit3:
        if (use_dma)
                dma_release_channel(host->dma_chan);
 err_exit2:
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
        clk_put(host->clk);
 err_exit1:
        lpc32xx_wp_enable(host);
@@ -822,7 +822,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
        if (use_dma)
                dma_release_channel(host->dma_chan);
 
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
        clk_put(host->clk);
 
        lpc32xx_wp_enable(host);
@@ -837,7 +837,7 @@ static int lpc32xx_nand_resume(struct platform_device *pdev)
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
 
        /* Re-enable NAND clock */
-       clk_enable(host->clk);
+       clk_prepare_enable(host->clk);
 
        /* Fresh init of NAND controller */
        lpc32xx_nand_setup(host);
@@ -856,7 +856,7 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
        lpc32xx_wp_enable(host);
 
        /* Disable clock */
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
        return 0;
 }
 
index abfec13868e5d8d3b95e3e9bd3e3e0e9759fd236..4f3d4eb17da0de7989a8a0f88c147442388bb1be 100644 (file)
 /**********************************************************************
 * slc_tac register definitions
 **********************************************************************/
+/* Computation of clock cycles on basis of controller and device clock rates */
+#define SLCTAC_CLOCKS(c, n, s) (min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s)
+
 /* Clock setting for RDY write sample wait time in 2*n clocks */
 #define SLCTAC_WDR(n)          (((n) & 0xF) << 28)
 /* Write pulse width in clock cycles, 1 to 16 clocks */
-#define SLCTAC_WWIDTH(n)       (((n) & 0xF) << 24)
+#define SLCTAC_WWIDTH(c, n)    (SLCTAC_CLOCKS(c, n, 24))
 /* Write hold time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_WHOLD(n)                (((n) & 0xF) << 20)
+#define SLCTAC_WHOLD(c, n)     (SLCTAC_CLOCKS(c, n, 20))
 /* Write setup time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_WSETUP(n)       (((n) & 0xF) << 16)
+#define SLCTAC_WSETUP(c, n)    (SLCTAC_CLOCKS(c, n, 16))
 /* Clock setting for RDY read sample wait time in 2*n clocks */
 #define SLCTAC_RDR(n)          (((n) & 0xF) << 12)
 /* Read pulse width in clock cycles, 1 to 16 clocks */
-#define SLCTAC_RWIDTH(n)       (((n) & 0xF) << 8)
+#define SLCTAC_RWIDTH(c, n)    (SLCTAC_CLOCKS(c, n, 8))
 /* Read hold time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_RHOLD(n)                (((n) & 0xF) << 4)
+#define SLCTAC_RHOLD(c, n)     (SLCTAC_CLOCKS(c, n, 4))
 /* Read setup time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_RSETUP(n)       (((n) & 0xF) << 0)
+#define SLCTAC_RSETUP(c, n)    (SLCTAC_CLOCKS(c, n, 0))
 
 /**********************************************************************
 * slc_ecc register definitions
@@ -240,13 +243,13 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
 
        /* Compute clock setup values */
        tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
-               SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) |
-               SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) |
-               SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) |
+               SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
+               SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
+               SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
                SLCTAC_RDR(host->ncfg->rdr_clks) |
-               SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) |
-               SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) |
-               SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup));
+               SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
+               SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
+               SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
        writel(tmp, SLC_TAC(host->io_base));
 }
 
@@ -660,7 +663,8 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
  */
 static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
                                            struct nand_chip *chip,
-                                           const uint8_t *buf, int oob_required)
+                                           const uint8_t *buf,
+                                           int oob_required, int page)
 {
        struct lpc32xx_nand_host *host = chip->priv;
        uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
@@ -689,7 +693,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
 static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
                                                struct nand_chip *chip,
                                                const uint8_t *buf,
-                                               int oob_required)
+                                               int oob_required, int page)
 {
        /* Raw writes can just use the FIFO interface */
        chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
@@ -810,7 +814,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
                res = -ENOENT;
                goto err_exit1;
        }
-       clk_enable(host->clk);
+       clk_prepare_enable(host->clk);
 
        /* Set NAND IO addresses and command/ready functions */
        chip->IO_ADDR_R = SLC_DATA(host->io_base);
@@ -915,7 +919,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 err_exit3:
        dma_release_channel(host->dma_chan);
 err_exit2:
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
 err_exit1:
        lpc32xx_wp_enable(host);
 
@@ -939,7 +943,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
        tmp &= ~SLCCFG_CE_LOW;
        writel(tmp, SLC_CTRL(host->io_base));
 
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
        lpc32xx_wp_enable(host);
 
        return 0;
@@ -951,7 +955,7 @@ static int lpc32xx_nand_resume(struct platform_device *pdev)
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
 
        /* Re-enable NAND clock */
-       clk_enable(host->clk);
+       clk_prepare_enable(host->clk);
 
        /* Fresh init of NAND controller */
        lpc32xx_nand_setup(host);
@@ -976,7 +980,7 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
        lpc32xx_wp_enable(host);
 
        /* Disable clock */
-       clk_disable(host->clk);
+       clk_disable_unprepare(host->clk);
 
        return 0;
 }
index 2a49b53c8db96b03a3b56a7cd039502ebfee0c9d..d6bbde4a5331775ccd6efd787e7ab231dfbd0b29 100644 (file)
@@ -659,6 +659,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip = &prv->chip;
 
        mtd->priv = chip;
+       mtd->dev.parent = dev;
        chip->priv = prv;
        prv->dev = dev;
 
@@ -841,6 +842,7 @@ static const struct of_device_id mpc5121_nfc_match[] = {
        { .compatible = "fsl,mpc5121-nfc", },
        {},
 };
+MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
 
 static struct platform_driver mpc5121_nfc_driver = {
        .probe          = mpc5121_nfc_probe,
index f04445b992f512c537018b81bf0d685a3ee2f62b..136e73a3e07e5359aee12877f96cfe81b71caba2 100644 (file)
@@ -1458,6 +1458,7 @@ static const struct of_device_id mxcnd_dt_ids[] = {
        },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
 
 static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
 {
@@ -1516,7 +1517,6 @@ static int mxcnd_probe(struct platform_device *pdev)
        this = &host->nand;
        mtd = &host->mtd;
        mtd->priv = this;
-       mtd->owner = THIS_MODULE;
        mtd->dev.parent = &pdev->dev;
        mtd->name = DRIVER_NAME;
 
index ceb68ca8277a9ebb49c763a72b0979f089b878bb..cc74142938b0a21410cc76e0adca5a58aa1ce26f 100644 (file)
@@ -543,23 +543,32 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
        }
 }
 
-/* Wait for the ready pin, after a command. The timeout is caught later. */
+/**
+ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ *
+ * Wait for the ready pin after a command, and warn if a timeout occurs.
+ */
 void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
-       unsigned long timeo = jiffies + msecs_to_jiffies(20);
+       unsigned long timeo = 400;
 
-       /* 400ms timeout */
        if (in_interrupt() || oops_in_progress)
-               return panic_nand_wait_ready(mtd, 400);
+               return panic_nand_wait_ready(mtd, timeo);
 
        led_trigger_event(nand_led_trigger, LED_FULL);
        /* Wait until command is processed or timeout occurs */
+       timeo = jiffies + msecs_to_jiffies(timeo);
        do {
                if (chip->dev_ready(mtd))
-                       break;
-               touch_softlockup_watchdog();
+                       goto out;
+               cond_resched();
        } while (time_before(jiffies, timeo));
+
+       pr_warn_ratelimited(
+               "timeout while waiting for chip to become ready\n");
+out:
        led_trigger_event(nand_led_trigger, LED_OFF);
 }
 EXPORT_SYMBOL_GPL(nand_wait_ready);
@@ -885,15 +894,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
  * @mtd: MTD device structure
  * @chip: NAND chip structure
  *
- * Wait for command done. This applies to erase and program only. Erase can
- * take up to 400ms and program up to 20ms according to general NAND and
- * SmartMedia specs.
+ * Wait for command done. This applies to erase and program only.
  */
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 
-       int status, state = chip->state;
-       unsigned long timeo = (state == FL_ERASING ? 400 : 20);
+       int status;
+       unsigned long timeo = 400;
 
        led_trigger_event(nand_led_trigger, LED_FULL);
 
@@ -909,7 +916,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
                panic_nand_wait(mtd, chip, timeo);
        else {
                timeo = jiffies + msecs_to_jiffies(timeo);
-               while (time_before(jiffies, timeo)) {
+               do {
                        if (chip->dev_ready) {
                                if (chip->dev_ready(mtd))
                                        break;
@@ -918,7 +925,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
                                        break;
                        }
                        cond_resched();
-               }
+               } while (time_before(jiffies, timeo));
        }
        led_trigger_event(nand_led_trigger, LED_OFF);
 
@@ -1100,6 +1107,134 @@ out:
 }
 EXPORT_SYMBOL(nand_lock);
 
+/**
+ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+ * @buf: buffer to test
+ * @len: buffer length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a buffer contains only 0xff, which means the underlying region
+ * has been erased and is ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region is not erased.
+ * Note: The logic of this function has been extracted from the memweight
+ * implementation, except that nand_check_erased_buf function exit before
+ * testing the whole buffer if the number of bitflips exceed the
+ * bitflips_threshold value.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold.
+ */
+static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+{
+       const unsigned char *bitmap = buf;
+       int bitflips = 0;
+       int weight;
+
+       for (; len && ((uintptr_t)bitmap) % sizeof(long);
+            len--, bitmap++) {
+               weight = hweight8(*bitmap);
+               bitflips += BITS_PER_BYTE - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       for (; len >= sizeof(long);
+            len -= sizeof(long), bitmap += sizeof(long)) {
+               weight = hweight_long(*((unsigned long *)bitmap));
+               bitflips += BITS_PER_LONG - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       for (; len > 0; len--, bitmap++) {
+               weight = hweight8(*bitmap);
+               bitflips += BITS_PER_BYTE - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       return bitflips;
+}
+
+/**
+ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+ *                              0xff data
+ * @data: data buffer to test
+ * @datalen: data length
+ * @ecc: ECC buffer
+ * @ecclen: ECC length
+ * @extraoob: extra OOB buffer
+ * @extraooblen: extra OOB length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a data buffer and its associated ECC and OOB data contains only
+ * 0xff pattern, which means the underlying region has been erased and is
+ * ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region as not erased.
+ *
+ * Note:
+ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+ *    different from the NAND page size. When fixing bitflips, ECC engines will
+ *    report the number of errors per chunk, and the NAND core infrastructure
+ *    expect you to return the maximum number of bitflips for the whole page.
+ *    This is why you should always use this function on a single chunk and
+ *    not on the whole page. After checking each chunk you should update your
+ *    max_bitflips value accordingly.
+ * 2/ When checking for bitflips in erased pages you should not only check
+ *    the payload data but also their associated ECC data, because a user might
+ *    have programmed almost all bits to 1 but a few. In this case, we
+ *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
+ *    this case.
+ * 3/ The extraoob argument is optional, and should be used if some of your OOB
+ *    data are protected by the ECC engine.
+ *    It could also be used if you support subpages and want to attach some
+ *    extra OOB data to an ECC chunk.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold. In case of success, the passed buffers are filled with 0xff.
+ */
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+                               void *ecc, int ecclen,
+                               void *extraoob, int extraooblen,
+                               int bitflips_threshold)
+{
+       int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+
+       data_bitflips = nand_check_erased_buf(data, datalen,
+                                             bitflips_threshold);
+       if (data_bitflips < 0)
+               return data_bitflips;
+
+       bitflips_threshold -= data_bitflips;
+
+       ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+       if (ecc_bitflips < 0)
+               return ecc_bitflips;
+
+       bitflips_threshold -= ecc_bitflips;
+
+       extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+                                                 bitflips_threshold);
+       if (extraoob_bitflips < 0)
+               return extraoob_bitflips;
+
+       if (data_bitflips)
+               memset(data, 0xff, datalen);
+
+       if (ecc_bitflips)
+               memset(ecc, 0xff, ecclen);
+
+       if (extraoob_bitflips)
+               memset(extraoob, 0xff, extraooblen);
+
+       return data_bitflips + ecc_bitflips + extraoob_bitflips;
+}
+EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+
 /**
  * nand_read_page_raw - [INTERN] read raw page data without ecc
  * @mtd: mtd info structure
@@ -2027,11 +2162,12 @@ out:
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
 static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required)
+                              const uint8_t *buf, int oob_required, int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
@@ -2046,12 +2182,14 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  *
  * We need a special oob layout and handling even when ECC isn't checked.
  */
 static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
                                        struct nand_chip *chip,
-                                       const uint8_t *buf, int oob_required)
+                                       const uint8_t *buf, int oob_required,
+                                       int page)
 {
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -2088,9 +2226,11 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  */
 static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required)
+                                const uint8_t *buf, int oob_required,
+                                int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -2106,7 +2246,7 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < chip->ecc.total; i++)
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-       return chip->ecc.write_page_raw(mtd, chip, buf, 1);
+       return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
 }
 
 /**
@@ -2115,9 +2255,11 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  */
 static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required)
+                                 const uint8_t *buf, int oob_required,
+                                 int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -2149,11 +2291,12 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @data_len:  data length
  * @buf:       data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  */
 static int nand_write_subpage_hwecc(struct mtd_info *mtd,
                                struct nand_chip *chip, uint32_t offset,
                                uint32_t data_len, const uint8_t *buf,
-                               int oob_required)
+                               int oob_required, int page)
 {
        uint8_t *oob_buf  = chip->oob_poi;
        uint8_t *ecc_calc = chip->buffers->ecccalc;
@@ -2208,13 +2351,15 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
  *
  * The hw generator calculates the error syndrome automatically. Therefore we
  * need a special oob layout and handling.
  */
 static int nand_write_page_syndrome(struct mtd_info *mtd,
                                    struct nand_chip *chip,
-                                   const uint8_t *buf, int oob_required)
+                                   const uint8_t *buf, int oob_required,
+                                   int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -2278,12 +2423,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (unlikely(raw))
                status = chip->ecc.write_page_raw(mtd, chip, buf,
-                                                       oob_required);
+                                                 oob_required, page);
        else if (subpage)
                status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
-                                                        buf, oob_required);
+                                                buf, oob_required, page);
        else
-               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required,
+                                             page);
 
        if (status < 0)
                return status;
@@ -3708,10 +3854,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        chip->chipsize = (uint64_t)type->chipsize << 20;
 
-       if (!type->pagesize && chip->init_size) {
-               /* Set the pagesize, oobsize, erasesize by the driver */
-               busw = chip->init_size(mtd, chip, id_data);
-       } else if (!type->pagesize) {
+       if (!type->pagesize) {
                /* Decode parameters from extended ID */
                nand_decode_ext_id(mtd, chip, id_data, &busw);
        } else {
@@ -3846,8 +3989,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        struct nand_flash_dev *type;
        int ret;
 
-       if (chip->dn) {
-               ret = nand_dt_init(mtd, chip, chip->dn);
+       if (chip->flash_node) {
+               ret = nand_dt_init(mtd, chip, chip->flash_node);
                if (ret)
                        return ret;
        }
index 63a1a36a3f4b4b804f7c4b389eacdc8c19d30a43..b1d4f813aedc12e36ed09e4c4fe8b552a66082b5 100644 (file)
@@ -1080,7 +1080,7 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        struct nand_bbt_descr *td = this->bbt_td;
        struct nand_bbt_descr *md = this->bbt_md;
 
-       len = mtd->size >> (this->bbt_erase_shift + 2);
+       len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
        /*
         * Allocate memory (2bit per block) and clear the memory bad block
         * table.
index 95d0cc49cfc2f4e37013f3e1bfc176d3c1b2ec78..b16d70aafd9ecb3d241fa91956cbe498a0fdb83e 100644 (file)
@@ -649,8 +649,7 @@ static void free_device(struct nandsim *ns)
                                kmem_cache_free(ns->nand_pages_slab,
                                                ns->pages[i].byte);
                }
-               if (ns->nand_pages_slab)
-                       kmem_cache_destroy(ns->nand_pages_slab);
+               kmem_cache_destroy(ns->nand_pages_slab);
                vfree(ns->pages);
        }
 }
index 67a1b3f911cfec41e723a6b6212c9551447544cc..4f0d62f9d22c1a26983a0c0faf2aab53d35ac824 100644 (file)
@@ -169,7 +169,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        chip->priv = ndfc;
 
        ndfc->mtd.priv = chip;
-       ndfc->mtd.owner = THIS_MODULE;
+       ndfc->mtd.dev.parent = &ndfc->ofdev->dev;
 
        flash_np = of_get_next_child(node, NULL);
        if (!flash_np)
index e58c644dd2205ec15985ee7c5de6217165052163..f0687f71fbd895eb90d8b7d880180450373197e2 100644 (file)
@@ -250,7 +250,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
        chip = &(nuc900_nand->chip);
 
        nuc900_nand->mtd.priv   = chip;
-       nuc900_nand->mtd.owner  = THIS_MODULE;
+       nuc900_nand->mtd.dev.parent = &pdev->dev;
        spin_lock_init(&nuc900_nand->lock);
 
        nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
index 60fa89939c24861e487354d033fb6c2b8d95eeaf..93f664cd1c906ade2deb3d16cb79ceae3e36024e 100644 (file)
@@ -1500,11 +1500,12 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
  * @chip:              nand chip info structure
  * @buf:               data buffer
  * @oob_required:      must write chip->oob_poi to OOB
+ * @page:              page
  *
  * Custom write page method evolved to support multi sector writing in one shot
  */
 static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required)
+                              const uint8_t *buf, int oob_required, int page)
 {
        int i;
        uint8_t *ecc_calc = chip->buffers->ecccalc;
@@ -1684,8 +1685,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        info->ecc_opt           = pdata->ecc_opt;
        mtd                     = &info->mtd;
        mtd->priv               = &info->nand;
-       mtd->name               = dev_name(&pdev->dev);
-       mtd->owner              = THIS_MODULE;
+       mtd->dev.parent         = &pdev->dev;
        nand_chip               = &info->nand;
        nand_chip->ecc.priv     = NULL;
 
index c3c6d305caa79d29c4b9863c6159f57b5714e7c6..ee83749fb1d355e67dbcb07c98b187f1e52e2a1a 100644 (file)
@@ -124,7 +124,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
        }
 
        mtd->priv = nc;
-       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
 
        nc->priv = board;
        nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
@@ -201,6 +201,7 @@ static const struct of_device_id orion_nand_of_match_table[] = {
        { .compatible = "marvell,orion-nand", },
        {},
 };
+MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
 #endif
 
 static struct platform_driver orion_nand_driver = {
index 66c345b420978a83ad8a153e7dc540752dfa8920..83cf021b9651242501ad49b63defc519de7918c5 100644 (file)
@@ -124,7 +124,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
 
        /* Link the private data with the MTD structure */
        pasemi_nand_mtd->priv = chip;
-       pasemi_nand_mtd->owner = THIS_MODULE;
+       pasemi_nand_mtd->dev.parent = &ofdev->dev;
 
        chip->IO_ADDR_R = of_iomap(np, 0);
        chip->IO_ADDR_W = chip->IO_ADDR_R;
index 717cf623fcdef81a761940cee99ceed616501d66..65b9dbbe6d6a4b899f30935f91ae491979f1d8a0 100644 (file)
@@ -59,8 +59,7 @@ static int plat_nand_probe(struct platform_device *pdev)
 
        data->chip.priv = &data;
        data->mtd.priv = &data->chip;
-       data->mtd.owner = THIS_MODULE;
-       data->mtd.name = dev_name(&pdev->dev);
+       data->mtd.dev.parent = &pdev->dev;
 
        data->chip.IO_ADDR_R = data->io_base;
        data->chip.IO_ADDR_W = data->io_base;
index 740983a3462644a306f8839929b40a21525b29dd..e453ae9a17fa3e884387685da46c75f8368ad29c 100644 (file)
@@ -15,7 +15,9 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/mtd/mtd.h>
 #define ARCH_HAS_DMA
 #endif
 
-#ifdef ARCH_HAS_DMA
-#include <mach/dma.h>
-#endif
-
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
 #define        CHIP_DELAY_TIMEOUT      msecs_to_jiffies(200)
@@ -78,7 +76,8 @@
 #define NDCR_ND_MODE           (0x3 << 21)
 #define NDCR_NAND_MODE         (0x0)
 #define NDCR_CLR_PG_CNT                (0x1 << 20)
-#define NDCR_STOP_ON_UNCOR     (0x1 << 19)
+#define NFCV1_NDCR_ARB_CNTL    (0x1 << 19)
+#define NFCV2_NDCR_STOP_ON_UNCOR       (0x1 << 19)
 #define NDCR_RD_ID_CNT_MASK    (0x7 << 16)
 #define NDCR_RD_ID_CNT(x)      (((x) << 16) & NDCR_RD_ID_CNT_MASK)
 
@@ -201,6 +200,10 @@ struct pxa3xx_nand_info {
        unsigned int            oob_buff_pos;
 
        /* DMA information */
+       struct scatterlist      sg;
+       enum dma_data_direction dma_dir;
+       struct dma_chan         *dma_chan;
+       dma_cookie_t            dma_cookie;
        int                     drcmr_dat;
        int                     drcmr_cmd;
 
@@ -208,8 +211,6 @@ struct pxa3xx_nand_info {
        unsigned char           *oob_buff;
        dma_addr_t              data_buff_phys;
        int                     data_dma_ch;
-       struct pxa_dma_desc     *data_desc;
-       dma_addr_t              data_desc_addr;
 
        struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
        unsigned int            state;
@@ -252,6 +253,25 @@ 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");
 
+struct pxa3xx_nand_timing {
+       unsigned int    tCH;  /* Enable signal hold time */
+       unsigned int    tCS;  /* Enable signal setup time */
+       unsigned int    tWH;  /* ND_nWE high duration */
+       unsigned int    tWP;  /* ND_nWE pulse time */
+       unsigned int    tRH;  /* ND_nRE high duration */
+       unsigned int    tRP;  /* ND_nRE pulse width */
+       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
+       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
+       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_flash {
+       uint32_t        chip_id;
+       unsigned int    flash_width;    /* Width of Flash memory (DWIDTH_M) */
+       unsigned int    dfc_width;      /* Width of flash controller(DWIDTH_C) */
+       struct pxa3xx_nand_timing *timing;      /* NAND Flash timing */
+};
+
 static struct pxa3xx_nand_timing timing[] = {
        { 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
        { 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
@@ -260,15 +280,14 @@ static struct pxa3xx_nand_timing timing[] = {
 };
 
 static struct pxa3xx_nand_flash builtin_flash_types[] = {
-{ "DEFAULT FLASH",      0,   0, 2048,  8,  8,    0, &timing[0] },
-{ "64MiB 16-bit",  0x46ec,  32,  512, 16, 16, 4096, &timing[1] },
-{ "256MiB 8-bit",  0xdaec,  64, 2048,  8,  8, 2048, &timing[1] },
-{ "4GiB 8-bit",    0xd7ec, 128, 4096,  8,  8, 8192, &timing[1] },
-{ "128MiB 8-bit",  0xa12c,  64, 2048,  8,  8, 1024, &timing[2] },
-{ "128MiB 16-bit", 0xb12c,  64, 2048, 16, 16, 1024, &timing[2] },
-{ "512MiB 8-bit",  0xdc2c,  64, 2048,  8,  8, 4096, &timing[2] },
-{ "512MiB 16-bit", 0xcc2c,  64, 2048, 16, 16, 4096, &timing[2] },
-{ "256MiB 16-bit", 0xba20,  64, 2048, 16, 16, 2048, &timing[3] },
+       { 0x46ec, 16, 16, &timing[1] },
+       { 0xdaec,  8,  8, &timing[1] },
+       { 0xd7ec,  8,  8, &timing[1] },
+       { 0xa12c,  8,  8, &timing[2] },
+       { 0xb12c, 16, 16, &timing[2] },
+       { 0xdc2c,  8,  8, &timing[2] },
+       { 0xcc2c, 16, 16, &timing[2] },
+       { 0xba20, 16, 16, &timing[3] },
 };
 
 static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
@@ -329,9 +348,6 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
        .oobfree = { }
 };
 
-/* Define a default flash type setting serve as flash detecting only */
-#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
-
 #define NDTR0_tCH(c)   (min((c), 7) << 19)
 #define NDTR0_tCS(c)   (min((c), 7) << 16)
 #define NDTR0_tWH(c)   (min((c), 7) << 11)
@@ -393,6 +409,128 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
        nand_writel(info, NDTR1CS0, ndtr1);
 }
 
+static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
+                                      const struct nand_sdr_timings *t)
+{
+       struct pxa3xx_nand_info *info = host->info_data;
+       struct nand_chip *chip = &host->chip;
+       unsigned long nand_clk = clk_get_rate(info->clk);
+       uint32_t ndtr0, ndtr1;
+
+       u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
+       u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
+       u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
+       u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
+       u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
+       u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
+       u32 tR = chip->chip_delay * 1000;
+       u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
+       u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
+
+       /* fallback to a default value if tR = 0 */
+       if (!tR)
+               tR = 20000;
+
+       ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
+               NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
+               NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
+               NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
+               NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
+               NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
+
+       ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
+               NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
+               NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
+
+       info->ndtr0cs0 = ndtr0;
+       info->ndtr1cs0 = ndtr1;
+       nand_writel(info, NDTR0CS0, ndtr0);
+       nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
+                                          unsigned int *flash_width,
+                                          unsigned int *dfc_width)
+{
+       struct nand_chip *chip = &host->chip;
+       struct pxa3xx_nand_info *info = host->info_data;
+       const struct pxa3xx_nand_flash *f = NULL;
+       int i, id, ntypes;
+
+       ntypes = ARRAY_SIZE(builtin_flash_types);
+
+       chip->cmdfunc(host->mtd, NAND_CMD_READID, 0x00, -1);
+
+       id = chip->read_byte(host->mtd);
+       id |= chip->read_byte(host->mtd) << 0x8;
+
+       for (i = 0; i < ntypes; i++) {
+               f = &builtin_flash_types[i];
+
+               if (f->chip_id == id)
+                       break;
+       }
+
+       if (i == ntypes) {
+               dev_err(&info->pdev->dev, "Error: timings not found\n");
+               return -EINVAL;
+       }
+
+       pxa3xx_nand_set_timing(host, f->timing);
+
+       *flash_width = f->flash_width;
+       *dfc_width = f->dfc_width;
+
+       return 0;
+}
+
+static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
+                                        int mode)
+{
+       const struct nand_sdr_timings *timings;
+
+       mode = fls(mode) - 1;
+       if (mode < 0)
+               mode = 0;
+
+       timings = onfi_async_timing_mode_to_sdr_timings(mode);
+       if (IS_ERR(timings))
+               return PTR_ERR(timings);
+
+       pxa3xx_nand_set_sdr_timing(host, timings);
+
+       return 0;
+}
+
+static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
+{
+       struct nand_chip *chip = &host->chip;
+       struct pxa3xx_nand_info *info = host->info_data;
+       unsigned int flash_width = 0, dfc_width = 0;
+       int mode, err;
+
+       mode = onfi_get_async_timing_mode(chip);
+       if (mode == ONFI_TIMING_MODE_UNKNOWN) {
+               err = pxa3xx_nand_init_timings_compat(host, &flash_width,
+                                                     &dfc_width);
+               if (err)
+                       return err;
+
+               if (flash_width == 16) {
+                       info->reg_ndcr |= NDCR_DWIDTH_M;
+                       chip->options |= NAND_BUSWIDTH_16;
+               }
+
+               info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
+       } else {
+               err = pxa3xx_nand_init_timings_onfi(host, mode);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 /*
  * Set the data and OOB size, depending on the selected
  * spare and ECC configuration.
@@ -468,6 +606,9 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
                ndcr &= ~NDCR_ND_RUN;
                nand_writel(info, NDCR, ndcr);
        }
+       if (info->dma_chan)
+               dmaengine_terminate_all(info->dma_chan);
+
        /* clear status bits */
        nand_writel(info, NDSR, NDSR_MASK);
 }
@@ -504,7 +645,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
                 * the polling on the last read.
                 */
                while (len > 8) {
-                       readsl(info->mmio_base + NDDB, data, 8);
+                       ioread32_rep(info->mmio_base + NDDB, data, 8);
 
                        ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
                                                         val & NDSR_RDDREQ, 1000, 5000);
@@ -519,7 +660,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
                }
        }
 
-       readsl(info->mmio_base + NDDB, data, len);
+       ioread32_rep(info->mmio_base + NDDB, data, len);
 }
 
 static void handle_data_pio(struct pxa3xx_nand_info *info)
@@ -559,57 +700,61 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        info->data_size -= do_bytes;
 }
 
-#ifdef ARCH_HAS_DMA
-static void start_data_dma(struct pxa3xx_nand_info *info)
+static void pxa3xx_nand_data_dma_irq(void *data)
 {
-       struct pxa_dma_desc *desc = info->data_desc;
-       int dma_len = ALIGN(info->data_size + info->oob_size, 32);
+       struct pxa3xx_nand_info *info = data;
+       struct dma_tx_state state;
+       enum dma_status status;
 
-       desc->ddadr = DDADR_STOP;
-       desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
+       status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
+       if (likely(status == DMA_COMPLETE)) {
+               info->state = STATE_DMA_DONE;
+       } else {
+               dev_err(&info->pdev->dev, "DMA error on data channel\n");
+               info->retcode = ERR_DMABUSERR;
+       }
+       dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+       nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+       enable_int(info, NDCR_INT_MASK);
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{
+       enum dma_transfer_direction direction;
+       struct dma_async_tx_descriptor *tx;
 
        switch (info->state) {
        case STATE_DMA_WRITING:
-               desc->dsadr = info->data_buff_phys;
-               desc->dtadr = info->mmio_phys + NDDB;
-               desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
+               info->dma_dir = DMA_TO_DEVICE;
+               direction = DMA_MEM_TO_DEV;
                break;
        case STATE_DMA_READING:
-               desc->dtadr = info->data_buff_phys;
-               desc->dsadr = info->mmio_phys + NDDB;
-               desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
+               info->dma_dir = DMA_FROM_DEVICE;
+               direction = DMA_DEV_TO_MEM;
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
                                info->state);
                BUG();
        }
-
-       DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch;
-       DDADR(info->data_dma_ch) = info->data_desc_addr;
-       DCSR(info->data_dma_ch) |= DCSR_RUN;
-}
-
-static void pxa3xx_nand_data_dma_irq(int channel, void *data)
-{
-       struct pxa3xx_nand_info *info = data;
-       uint32_t dcsr;
-
-       dcsr = DCSR(channel);
-       DCSR(channel) = dcsr;
-
-       if (dcsr & DCSR_BUSERR) {
-               info->retcode = ERR_DMABUSERR;
+       info->sg.length = info->data_size +
+               (info->oob_size ? info->spare_size + info->ecc_size : 0);
+       dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+       tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
+                                    DMA_PREP_INTERRUPT);
+       if (!tx) {
+               dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
+               return;
        }
-
-       info->state = STATE_DMA_DONE;
-       enable_int(info, NDCR_INT_MASK);
-       nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+       tx->callback = pxa3xx_nand_data_dma_irq;
+       tx->callback_param = info;
+       info->dma_cookie = dmaengine_submit(tx);
+       dma_async_issue_pending(info->dma_chan);
+       dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
+               __func__, direction, info->dma_cookie, info->sg.length);
 }
-#else
-static void start_data_dma(struct pxa3xx_nand_info *info)
-{}
-#endif
 
 static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
 {
@@ -1128,7 +1273,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
 }
 
 static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf, int oob_required)
+               struct nand_chip *chip, const uint8_t *buf, int oob_required,
+               int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1241,45 +1387,23 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
        return NAND_STATUS_READY;
 }
 
-static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
-                                   const struct pxa3xx_nand_flash *f)
+static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info)
 {
        struct platform_device *pdev = info->pdev;
        struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct pxa3xx_nand_host *host = info->host[info->cs];
-       uint32_t ndcr = 0x0; /* enable all interrupts */
-
-       if (f->page_size != 2048 && f->page_size != 512) {
-               dev_err(&pdev->dev, "Current only support 2048 and 512 size\n");
-               return -EINVAL;
-       }
-
-       if (f->flash_width != 16 && f->flash_width != 8) {
-               dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n");
-               return -EINVAL;
-       }
-
-       /* calculate addressing information */
-       host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
-
-       if (f->num_blocks * f->page_per_block > 65536)
-               host->row_addr_cycles = 3;
-       else
-               host->row_addr_cycles = 2;
-
-       ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
-       ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
-       ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
-       ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
-       ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
-       ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
-
-       ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
-       ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+       struct mtd_info *mtd = host->mtd;
+       struct nand_chip *chip = mtd->priv;
 
-       info->reg_ndcr = ndcr;
+       /* configure default flash values */
+       info->reg_ndcr = 0x0; /* enable all interrupts */
+       info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+       info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
+       info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+       info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
+       info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
+       info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
 
-       pxa3xx_nand_set_timing(host, f->timing);
        return 0;
 }
 
@@ -1289,42 +1413,57 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
 
        /* Set an initial chunk size */
        info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
-       info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
+       info->reg_ndcr = ndcr &
+               ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
        info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
        info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
        return 0;
 }
 
-#ifdef ARCH_HAS_DMA
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
        struct platform_device *pdev = info->pdev;
-       int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc);
+       struct dma_slave_config config;
+       dma_cap_mask_t mask;
+       struct pxad_param param;
+       int ret;
 
-       if (use_dma == 0) {
-               info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-               if (info->data_buff == NULL)
-                       return -ENOMEM;
+       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+       if (info->data_buff == NULL)
+               return -ENOMEM;
+       if (use_dma == 0)
                return 0;
-       }
 
-       info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size,
-                               &info->data_buff_phys, GFP_KERNEL);
-       if (info->data_buff == NULL) {
-               dev_err(&pdev->dev, "failed to allocate dma buffer\n");
-               return -ENOMEM;
-       }
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
 
-       info->data_desc = (void *)info->data_buff + data_desc_offset;
-       info->data_desc_addr = info->data_buff_phys + data_desc_offset;
+       sg_init_one(&info->sg, info->data_buff, info->buf_size);
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       param.prio = PXAD_PRIO_LOWEST;
+       param.drcmr = info->drcmr_dat;
+       info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
+                                                         &param, &pdev->dev,
+                                                         "data");
+       if (!info->dma_chan) {
+               dev_err(&pdev->dev, "unable to request data dma channel\n");
+               return -ENODEV;
+       }
 
-       info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
-                               pxa3xx_nand_data_dma_irq, info);
-       if (info->data_dma_ch < 0) {
-               dev_err(&pdev->dev, "failed to request data dma\n");
-               dma_free_coherent(&pdev->dev, info->buf_size,
-                               info->data_buff, info->data_buff_phys);
-               return info->data_dma_ch;
+       memset(&config, 0, sizeof(config));
+       config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       config.src_addr = info->mmio_phys + NDDB;
+       config.dst_addr = info->mmio_phys + NDDB;
+       config.src_maxburst = 32;
+       config.dst_maxburst = 32;
+       ret = dmaengine_slave_config(info->dma_chan, &config);
+       if (ret < 0) {
+               dev_err(&info->pdev->dev,
+                       "dma channel configuration failed: %d\n",
+                       ret);
+               return ret;
        }
 
        /*
@@ -1337,43 +1476,30 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 
 static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
 {
-       struct platform_device *pdev = info->pdev;
        if (info->use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_coherent(&pdev->dev, info->buf_size,
-                                 info->data_buff, info->data_buff_phys);
-       } else {
-               kfree(info->data_buff);
+               dmaengine_terminate_all(info->dma_chan);
+               dma_release_channel(info->dma_chan);
        }
-}
-#else
-static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
-{
-       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-       if (info->data_buff == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
-{
        kfree(info->data_buff);
 }
-#endif
 
-static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
+static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host)
 {
+       struct pxa3xx_nand_info *info = host->info_data;
        struct mtd_info *mtd;
        struct nand_chip *chip;
+       const struct nand_sdr_timings *timings;
        int ret;
 
        mtd = info->host[info->cs]->mtd;
        chip = mtd->priv;
 
        /* use the common timing to make a try */
-       ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
-       if (ret)
-               return ret;
+       timings = onfi_async_timing_mode_to_sdr_timings(0);
+       if (IS_ERR(timings))
+               return PTR_ERR(timings);
+
+       pxa3xx_nand_set_sdr_timing(host, timings);
 
        chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
        ret = chip->waitfunc(mtd, chip);
@@ -1458,12 +1584,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        struct pxa3xx_nand_info *info = host->info_data;
        struct platform_device *pdev = info->pdev;
        struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
-       const struct pxa3xx_nand_flash *f = NULL;
        struct nand_chip *chip = mtd->priv;
-       uint32_t id = -1;
-       uint64_t chipsize;
-       int i, ret, num;
+       int ret;
        uint16_t ecc_strength, ecc_step;
 
        if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
@@ -1472,7 +1594,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        /* Set a default chunk size */
        info->chunk_size = 512;
 
-       ret = pxa3xx_nand_sensing(info);
+       ret = pxa3xx_nand_config_flash(info);
+       if (ret)
+               return ret;
+
+       ret = pxa3xx_nand_sensing(host);
        if (ret) {
                dev_info(&info->pdev->dev, "There is no chip on cs %d!\n",
                         info->cs);
@@ -1480,54 +1606,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
                return ret;
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
-       id = *((uint16_t *)(info->data_buff));
-       if (id != 0)
-               dev_info(&info->pdev->dev, "Detect a flash id %x\n", id);
-       else {
-               dev_warn(&info->pdev->dev,
-                        "Read out ID 0, potential timing set wrong!!\n");
-
-               return -EINVAL;
-       }
-
-       num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1;
-       for (i = 0; i < num; i++) {
-               if (i < pdata->num_flash)
-                       f = pdata->flash + i;
-               else
-                       f = &builtin_flash_types[i - pdata->num_flash + 1];
-
-               /* find the chip in default list */
-               if (f->chip_id == id)
-                       break;
-       }
-
-       if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
-               dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
-
-               return -EINVAL;
-       }
-
-       ret = pxa3xx_nand_config_flash(info, f);
-       if (ret) {
-               dev_err(&info->pdev->dev, "ERROR! Configure failed\n");
-               return ret;
-       }
-
-       memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids));
-
-       pxa3xx_flash_ids[0].name = f->name;
-       pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff;
-       pxa3xx_flash_ids[0].pagesize = f->page_size;
-       chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size;
-       pxa3xx_flash_ids[0].chipsize = chipsize >> 20;
-       pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block;
-       if (f->flash_width == 16)
-               pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16;
-       pxa3xx_flash_ids[1].name = NULL;
-       def = pxa3xx_flash_ids;
 KEEP_CONFIG:
+       info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
        if (info->reg_ndcr & NDCR_DWIDTH_M)
                chip->options |= NAND_BUSWIDTH_16;
 
@@ -1535,9 +1615,18 @@ KEEP_CONFIG:
        if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
                nand_writel(info, NDECCCTRL, 0x0);
 
-       if (nand_scan_ident(mtd, 1, def))
+       if (nand_scan_ident(mtd, 1, NULL))
                return -ENODEV;
 
+       if (!pdata->keep_config) {
+               ret = pxa3xx_nand_init(host);
+               if (ret) {
+                       dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        if (pdata->flash_bbt) {
                /*
                 * We'll use a bad block table stored in-flash and don't
@@ -1635,7 +1724,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                host->cs = cs;
                host->info_data = info;
                mtd->priv = host;
-               mtd->owner = THIS_MODULE;
+               mtd->dev.parent = &pdev->dev;
 
                chip->ecc.read_page     = pxa3xx_nand_read_page_hwecc;
                chip->ecc.write_page    = pxa3xx_nand_write_page_hwecc;
@@ -1662,34 +1751,23 @@ static int alloc_nand_resource(struct platform_device *pdev)
                return ret;
 
        if (use_dma) {
-               /*
-                * This is a dirty hack to make this driver work from
-                * devicetree bindings. It can be removed once we have
-                * a prober DMA controller framework for DT.
-                */
-               if (pdev->dev.of_node &&
-                   of_machine_is_compatible("marvell,pxa3xx")) {
-                       info->drcmr_dat = 97;
-                       info->drcmr_cmd = 99;
-               } else {
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-                       if (r == NULL) {
-                               dev_err(&pdev->dev,
-                                       "no resource defined for data DMA\n");
-                               ret = -ENXIO;
-                               goto fail_disable_clk;
-                       }
-                       info->drcmr_dat = r->start;
-
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-                       if (r == NULL) {
-                               dev_err(&pdev->dev,
-                                       "no resource defined for cmd DMA\n");
-                               ret = -ENXIO;
-                               goto fail_disable_clk;
-                       }
-                       info->drcmr_cmd = r->start;
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (r == NULL) {
+                       dev_err(&pdev->dev,
+                               "no resource defined for data DMA\n");
+                       ret = -ENXIO;
+                       goto fail_disable_clk;
+               }
+               info->drcmr_dat = r->start;
+
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (r == NULL) {
+                       dev_err(&pdev->dev,
+                               "no resource defined for cmd DMA\n");
+                       ret = -ENXIO;
+                       goto fail_disable_clk;
                }
+               info->drcmr_cmd = r->start;
        }
 
        irq = platform_get_irq(pdev, 0);
@@ -1754,6 +1832,16 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
                free_irq(irq, info);
        pxa3xx_nand_free_buff(info);
 
+       /*
+        * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
+        * In order to prevent a lockup of the system bus, the DFI bus
+        * arbitration is granted to SMC upon driver removal. This is done by
+        * setting the x_ARB_CNTL bit, which also prevents the NAND to have
+        * access to the bus anymore.
+        */
+       nand_writel(info, NDCR,
+                   (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
+                   NFCV1_NDCR_ARB_CNTL);
        clk_disable_unprepare(info->clk);
 
        for (cs = 0; cs < pdata->num_cs; cs++)
@@ -1800,15 +1888,16 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        struct pxa3xx_nand_platform_data *pdata;
        struct mtd_part_parser_data ppdata = {};
        struct pxa3xx_nand_info *info;
-       int ret, cs, probe_success;
+       int ret, cs, probe_success, dma_available;
 
-#ifndef ARCH_HAS_DMA
-       if (use_dma) {
+       dma_available = IS_ENABLED(CONFIG_ARM) &&
+               (IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
+       if (use_dma && !dma_available) {
                use_dma = 0;
                dev_warn(&pdev->dev,
                         "This platform can't do DMA on this device\n");
        }
-#endif
+
        ret = pxa3xx_nand_probe_dt(pdev);
        if (ret)
                return ret;
@@ -1861,35 +1950,22 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
+static int pxa3xx_nand_suspend(struct device *dev)
 {
-       struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
-       struct pxa3xx_nand_platform_data *pdata;
-       struct mtd_info *mtd;
-       int cs;
+       struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
 
-       pdata = dev_get_platdata(&pdev->dev);
        if (info->state) {
-               dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
+               dev_err(dev, "driver busy, state = %d\n", info->state);
                return -EAGAIN;
        }
 
-       for (cs = 0; cs < pdata->num_cs; cs++) {
-               mtd = info->host[cs]->mtd;
-               mtd_suspend(mtd);
-       }
-
        return 0;
 }
 
-static int pxa3xx_nand_resume(struct platform_device *pdev)
+static int pxa3xx_nand_resume(struct device *dev)
 {
-       struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
-       struct pxa3xx_nand_platform_data *pdata;
-       struct mtd_info *mtd;
-       int cs;
+       struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
 
-       pdata = dev_get_platdata(&pdev->dev);
        /* We don't want to handle interrupt without calling mtd routine */
        disable_int(info, NDCR_INT_MASK);
 
@@ -1907,10 +1983,6 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
         * all status before resume
         */
        nand_writel(info, NDSR, NDSR_MASK);
-       for (cs = 0; cs < pdata->num_cs; cs++) {
-               mtd = info->host[cs]->mtd;
-               mtd_resume(mtd);
-       }
 
        return 0;
 }
@@ -1919,15 +1991,19 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
 #define pxa3xx_nand_resume     NULL
 #endif
 
+static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
+       .suspend        = pxa3xx_nand_suspend,
+       .resume         = pxa3xx_nand_resume,
+};
+
 static struct platform_driver pxa3xx_nand_driver = {
        .driver = {
                .name   = "pxa3xx-nand",
                .of_match_table = pxa3xx_nand_dt_ids,
+               .pm     = &pxa3xx_nand_pm_ops,
        },
        .probe          = pxa3xx_nand_probe,
        .remove         = pxa3xx_nand_remove,
-       .suspend        = pxa3xx_nand_suspend,
-       .resume         = pxa3xx_nand_resume,
 };
 
 module_platform_driver(pxa3xx_nand_driver);
index cc6bac537f5a286a9cfd7027d0da2555886e5dbe..d8bb2be327f11633b4ae765e68aa570888cba278 100644 (file)
@@ -641,7 +641,6 @@ static int r852_register_nand_device(struct r852_device *dev)
 
        WARN_ON(dev->card_registred);
 
-       dev->mtd->owner = THIS_MODULE;
        dev->mtd->priv = dev->chip;
        dev->mtd->dev.parent = &dev->pci_dev->dev;
 
index 381f67ac6b5a0626a562ffb1508b66cb263fa245..05105cadd0db90ea0db38d6e022fd0db7bfaefaa 100644 (file)
@@ -832,7 +832,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 
        nmtd->info         = info;
        nmtd->mtd.priv     = chip;
-       nmtd->mtd.owner    = THIS_MODULE;
        nmtd->set          = set;
 
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
@@ -1016,6 +1015,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                pr_debug("initialising set %d (%p, info %p)\n",
                         setno, nmtd, info);
 
+               nmtd->mtd.dev.parent = &pdev->dev;
                s3c2410_nand_init_chip(info, nmtd, sets);
 
                nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
index c3ce81c1a7163a71d3ceee81ea248e11f45925dc..bcba1a924c75f25e0d8ef4ac20f841e6d4a1ae33 100644 (file)
@@ -569,7 +569,8 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                  const uint8_t *buf, int oob_required)
+                                 const uint8_t *buf, int oob_required,
+                                 int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1123,6 +1124,7 @@ static int flctl_probe(struct platform_device *pdev)
        flctl_mtd = &flctl->mtd;
        nand = &flctl->chip;
        flctl_mtd->priv = nand;
+       flctl_mtd->dev.parent = &pdev->dev;
        flctl->pdev = pdev;
        flctl->hwecc = pdata->has_hwecc;
        flctl->holden = pdata->use_holden;
index 842c47a451a0dcfedd21b28b103804b684212e13..082b6009736d921e0215c59854baeb3ee0ae3ec4 100644 (file)
@@ -144,7 +144,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 
        /* Link the private data with the MTD structure */
        sharpsl->mtd.priv = this;
-       sharpsl->mtd.owner = THIS_MODULE;
+       sharpsl->mtd.dev.parent = &pdev->dev;
 
        platform_set_drvdata(pdev, sharpsl);
 
index d71062273f558790fe255c18f11117a190b14d8d..b94f53427f0f9616ac784afae73c5a9e078ccdbf 100644 (file)
@@ -167,7 +167,6 @@ static int socrates_nand_probe(struct platform_device *ofdev)
        nand_chip->priv = host;         /* link the private data structures */
        mtd->priv = nand_chip;
        mtd->name = "socrates_nand";
-       mtd->owner = THIS_MODULE;
        mtd->dev.parent = &ofdev->dev;
        ppdata.of_node = ofdev->dev.of_node;
 
index e7d333c162befd274f891b8674b5ca8fd905315e..824711845c44cb44a453b56b39c7f255bd43ae1b 100644 (file)
 #define NFC_REG_ECC_CTL                0x0034
 #define NFC_REG_ECC_ST         0x0038
 #define NFC_REG_DEBUG          0x003C
-#define NFC_REG_ECC_CNT0       0x0040
-#define NFC_REG_ECC_CNT1       0x0044
-#define NFC_REG_ECC_CNT2       0x0048
-#define NFC_REG_ECC_CNT3       0x004c
-#define NFC_REG_USER_DATA_BASE 0x0050
+#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
+#define NFC_REG_USER_DATA(x)   (0x0050 + ((x) * 4))
 #define NFC_REG_SPARE_AREA     0x00A0
 #define NFC_RAM0_BASE          0x0400
 #define NFC_RAM1_BASE          0x0800
 /* define bit use in NFC_CTL */
 #define NFC_EN                 BIT(0)
 #define NFC_RESET              BIT(1)
-#define NFC_BUS_WIDYH          BIT(2)
-#define NFC_RB_SEL             BIT(3)
-#define NFC_CE_SEL             GENMASK(26, 24)
+#define NFC_BUS_WIDTH_MSK      BIT(2)
+#define NFC_BUS_WIDTH_8                (0 << 2)
+#define NFC_BUS_WIDTH_16       (1 << 2)
+#define NFC_RB_SEL_MSK         BIT(3)
+#define NFC_RB_SEL(x)          ((x) << 3)
+#define NFC_CE_SEL_MSK         GENMASK(26, 24)
+#define NFC_CE_SEL(x)          ((x) << 24)
 #define NFC_CE_CTL             BIT(6)
-#define NFC_CE_CTL1            BIT(7)
-#define NFC_PAGE_SIZE          GENMASK(11, 8)
+#define NFC_PAGE_SHIFT_MSK     GENMASK(11, 8)
+#define NFC_PAGE_SHIFT(x)      (((x) < 10 ? 0 : (x) - 10) << 8)
 #define NFC_SAM                        BIT(12)
 #define NFC_RAM_METHOD         BIT(14)
 #define NFC_DEBUG_CTL          BIT(31)
 #define NFC_CMD_FIFO_STATUS    BIT(3)
 #define NFC_STA                        BIT(4)
 #define NFC_NATCH_INT_FLAG     BIT(5)
-#define NFC_RB_STATE0          BIT(8)
-#define NFC_RB_STATE1          BIT(9)
-#define NFC_RB_STATE2          BIT(10)
-#define NFC_RB_STATE3          BIT(11)
+#define NFC_RB_STATE(x)                BIT(x + 8)
 
 /* define bit use in NFC_INT */
 #define NFC_B2R_INT_ENABLE     BIT(0)
        (((tCAD) & 0x7) << 8))
 
 /* define bit use in NFC_CMD */
-#define NFC_CMD_LOW_BYTE       GENMASK(7, 0)
-#define NFC_CMD_HIGH_BYTE      GENMASK(15, 8)
-#define NFC_ADR_NUM            GENMASK(18, 16)
+#define NFC_CMD_LOW_BYTE_MSK   GENMASK(7, 0)
+#define NFC_CMD_HIGH_BYTE_MSK  GENMASK(15, 8)
+#define NFC_CMD(x)             (x)
+#define NFC_ADR_NUM_MSK                GENMASK(18, 16)
+#define NFC_ADR_NUM(x)         (((x) - 1) << 16)
 #define NFC_SEND_ADR           BIT(19)
 #define NFC_ACCESS_DIR         BIT(20)
 #define NFC_DATA_TRANS         BIT(21)
 #define NFC_ROW_AUTO_INC       BIT(27)
 #define NFC_SEND_CMD3          BIT(28)
 #define NFC_SEND_CMD4          BIT(29)
-#define NFC_CMD_TYPE           GENMASK(31, 30)
+#define NFC_CMD_TYPE_MSK       GENMASK(31, 30)
+#define NFC_NORMAL_OP          (0 << 30)
+#define NFC_ECC_OP             (1 << 30)
+#define NFC_PAGE_OP            (2 << 30)
 
 /* define bit use in NFC_RCMD_SET */
-#define NFC_READ_CMD           GENMASK(7, 0)
-#define NFC_RANDOM_READ_CMD0   GENMASK(15, 8)
-#define NFC_RANDOM_READ_CMD1   GENMASK(23, 16)
+#define NFC_READ_CMD_MSK       GENMASK(7, 0)
+#define NFC_RND_READ_CMD0_MSK  GENMASK(15, 8)
+#define NFC_RND_READ_CMD1_MSK  GENMASK(23, 16)
 
 /* define bit use in NFC_WCMD_SET */
-#define NFC_PROGRAM_CMD                GENMASK(7, 0)
-#define NFC_RANDOM_WRITE_CMD   GENMASK(15, 8)
-#define NFC_READ_CMD0          GENMASK(23, 16)
-#define NFC_READ_CMD1          GENMASK(31, 24)
+#define NFC_PROGRAM_CMD_MSK    GENMASK(7, 0)
+#define NFC_RND_WRITE_CMD_MSK  GENMASK(15, 8)
+#define NFC_READ_CMD0_MSK      GENMASK(23, 16)
+#define NFC_READ_CMD1_MSK      GENMASK(31, 24)
 
 /* define bit use in NFC_ECC_CTL */
 #define NFC_ECC_EN             BIT(0)
 #define NFC_ECC_PIPELINE       BIT(3)
 #define NFC_ECC_EXCEPTION      BIT(4)
-#define NFC_ECC_BLOCK_SIZE     BIT(5)
+#define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
 #define NFC_RANDOM_EN          BIT(9)
 #define NFC_RANDOM_DIRECTION   BIT(10)
-#define NFC_ECC_MODE_SHIFT     12
-#define NFC_ECC_MODE           GENMASK(15, 12)
-#define NFC_RANDOM_SEED                GENMASK(30, 16)
+#define NFC_ECC_MODE_MSK       GENMASK(15, 12)
+#define NFC_ECC_MODE(x)                ((x) << 12)
+#define NFC_RANDOM_SEED_MSK    GENMASK(30, 16)
+#define NFC_RANDOM_SEED(x)     ((x) << 16)
 
-/* NFC_USER_DATA helper macros */
-#define NFC_BUF_TO_USER_DATA(buf)      ((buf)[0] | ((buf)[1] << 8) | \
-                                       ((buf)[2] << 16) | ((buf)[3] << 24))
+/* define bit use in NFC_ECC_ST */
+#define NFC_ECC_ERR(x)         BIT(x)
+#define NFC_ECC_PAT_FOUND(x)   BIT(x + 16)
+#define NFC_ECC_ERR_CNT(b, x)  (((x) >> ((b) * 8)) & 0xff)
 
 #define NFC_DEFAULT_TIMEOUT_MS 1000
 
@@ -360,13 +365,13 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
        switch (rb->type) {
        case RB_NATIVE:
                ret = !!(readl(nfc->regs + NFC_REG_ST) &
-                        (NFC_RB_STATE0 << rb->info.nativeid));
+                        NFC_RB_STATE(rb->info.nativeid));
                if (ret)
                        break;
 
                sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo);
                ret = !!(readl(nfc->regs + NFC_REG_ST) &
-                        (NFC_RB_STATE0 << rb->info.nativeid));
+                        NFC_RB_STATE(rb->info.nativeid));
                break;
        case RB_GPIO:
                ret = gpio_get_value(rb->info.gpio);
@@ -396,19 +401,19 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
                return;
 
        ctl = readl(nfc->regs + NFC_REG_CTL) &
-             ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN);
+             ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
 
        if (chip >= 0) {
                sel = &sunxi_nand->sels[chip];
 
-               ctl |= (sel->cs << 24) | NFC_EN |
-                      (((nand->page_shift - 10) & 0xf) << 8);
+               ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
+                      NFC_PAGE_SHIFT(nand->page_shift - 10);
                if (sel->rb.type == RB_NONE) {
                        nand->dev_ready = NULL;
                } else {
                        nand->dev_ready = sunxi_nfc_dev_ready;
                        if (sel->rb.type == RB_NATIVE)
-                               ctl |= (sel->rb.info.nativeid << 3);
+                               ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
                }
 
                writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
@@ -534,155 +539,244 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
        sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
 }
 
-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
-                                     struct nand_chip *chip, uint8_t *buf,
-                                     int oob_required, int page)
+static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 {
-       struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-       struct nand_ecclayout *layout = ecc->layout;
-       struct sunxi_nand_hw_ecc *data = ecc->priv;
-       unsigned int max_bitflips = 0;
-       int offset;
-       int ret;
-       u32 tmp;
-       int i;
-       int cnt;
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
+       u32 ecc_ctl;
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
-       tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
-              NFC_ECC_EXCEPTION;
+       ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+       ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
+                    NFC_ECC_BLOCK_SIZE_MSK);
+       ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION;
 
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
+}
 
-       for (i = 0; i < ecc->steps; i++) {
-               if (i)
-                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
+static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 
-               offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
+       writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
+              nfc->regs + NFC_REG_ECC_CTL);
+}
 
-               chip->read_buf(mtd, NULL, ecc->size);
+static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
+{
+       buf[0] = user_data;
+       buf[1] = user_data >> 8;
+       buf[2] = user_data >> 16;
+       buf[3] = user_data >> 24;
+}
 
-               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
+                                      u8 *data, int data_off,
+                                      u8 *oob, int oob_off,
+                                      int *cur_off,
+                                      unsigned int *max_bitflips)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+       u32 status;
+       int ret;
 
-               ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-               if (ret)
-                       return ret;
+       if (*cur_off != data_off)
+               nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
 
-               tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
-               writel(tmp, nfc->regs + NFC_REG_CMD);
+       sunxi_nfc_read_buf(mtd, NULL, ecc->size);
 
-               ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
-               if (ret)
-                       return ret;
+       if (data_off + ecc->size != oob_off)
+               nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
 
-               memcpy_fromio(buf + (i * ecc->size),
-                             nfc->regs + NFC_RAM0_BASE, ecc->size);
+       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+       if (ret)
+               return ret;
 
-               if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
-                       mtd->ecc_stats.failed++;
-               } else {
-                       tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff;
-                       mtd->ecc_stats.corrected += tmp;
-                       max_bitflips = max_t(unsigned int, max_bitflips, tmp);
-               }
+       writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
+              nfc->regs + NFC_REG_CMD);
 
-               if (oob_required) {
-                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+       ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       if (ret)
+               return ret;
 
-                       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-                       if (ret)
-                               return ret;
+       status = readl(nfc->regs + NFC_REG_ECC_ST);
+       ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
 
-                       offset -= mtd->writesize;
-                       chip->read_buf(mtd, chip->oob_poi + offset,
-                                     ecc->bytes + 4);
-               }
+       memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
+
+       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+       sunxi_nfc_read_buf(mtd, oob, ecc->bytes + 4);
+
+       if (status & NFC_ECC_ERR(0)) {
+               ret = nand_check_erased_ecc_chunk(data, ecc->size,
+                                                 oob, ecc->bytes + 4,
+                                                 NULL, 0, ecc->strength);
+       } else {
+               /*
+                * The engine protects 4 bytes of OOB data per chunk.
+                * Retrieve the corrected OOB bytes.
+                */
+               sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)),
+                                          oob);
        }
 
-       if (oob_required) {
-               cnt = ecc->layout->oobfree[ecc->steps].length;
-               if (cnt > 0) {
-                       offset = mtd->writesize +
-                                ecc->layout->oobfree[ecc->steps].offset;
-                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
-                       offset -= mtd->writesize;
-                       chip->read_buf(mtd, chip->oob_poi + offset, cnt);
-               }
+       if (ret < 0) {
+               mtd->ecc_stats.failed++;
+       } else {
+               mtd->ecc_stats.corrected += ret;
+               *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
        }
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~NFC_ECC_EN;
+       *cur_off = oob_off + ecc->bytes + 4;
 
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       return 0;
+}
 
-       return max_bitflips;
+static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
+                                           u8 *oob, int *cur_off)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+       int offset = ((ecc->bytes + 4) * ecc->steps);
+       int len = mtd->oobsize - offset;
+
+       if (len <= 0)
+               return;
+
+       if (*cur_off != offset)
+               nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                             offset + mtd->writesize, -1);
+
+       sunxi_nfc_read_buf(mtd, oob + offset, len);
+
+       *cur_off = mtd->oobsize + mtd->writesize;
 }
 
-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
-                                      struct nand_chip *chip,
-                                      const uint8_t *buf, int oob_required)
+static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
 {
-       struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-       struct nand_ecclayout *layout = ecc->layout;
-       struct sunxi_nand_hw_ecc *data = ecc->priv;
-       int offset;
+       return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
+                                       const u8 *data, int data_off,
+                                       const u8 *oob, int oob_off,
+                                       int *cur_off)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
        int ret;
-       u32 tmp;
-       int i;
-       int cnt;
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
-       tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
-              NFC_ECC_EXCEPTION;
+       if (data_off != *cur_off)
+               nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
 
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_write_buf(mtd, data, ecc->size);
 
-       for (i = 0; i < ecc->steps; i++) {
-               if (i)
-                       chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
+       /* Fill OOB data in */
+       writel(sunxi_nfc_buf_to_user_data(oob),
+              nfc->regs + NFC_REG_USER_DATA(0));
 
-               chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
+       if (data_off + ecc->size != oob_off)
+               nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
 
-               offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
+       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+       if (ret)
+               return ret;
 
-               /* Fill OOB data in */
-               writel(NFC_BUF_TO_USER_DATA(chip->oob_poi +
-                                           layout->oobfree[i].offset),
-                      nfc->regs + NFC_REG_USER_DATA_BASE);
+       writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+              NFC_ACCESS_DIR | NFC_ECC_OP,
+              nfc->regs + NFC_REG_CMD);
 
-               chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
+       ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       if (ret)
+               return ret;
 
-               ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-               if (ret)
-                       return ret;
+       *cur_off = oob_off + ecc->bytes + 4;
 
-               tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
-                     (1 << 30);
-               writel(tmp, nfc->regs + NFC_REG_CMD);
-               ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       return 0;
+}
+
+static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
+                                            u8 *oob, int *cur_off)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+       int offset = ((ecc->bytes + 4) * ecc->steps);
+       int len = mtd->oobsize - offset;
+
+       if (len <= 0)
+               return;
+
+       if (*cur_off != offset)
+               nand->cmdfunc(mtd, NAND_CMD_RNDIN,
+                             offset + mtd->writesize, -1);
+
+       sunxi_nfc_write_buf(mtd, oob + offset, len);
+
+       *cur_off = mtd->oobsize + mtd->writesize;
+}
+
+static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
+                                     struct nand_chip *chip, uint8_t *buf,
+                                     int oob_required, int page)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       unsigned int max_bitflips = 0;
+       int ret, i, cur_off = 0;
+
+       sunxi_nfc_hw_ecc_enable(mtd);
+
+       for (i = 0; i < ecc->steps; i++) {
+               int data_off = i * ecc->size;
+               int oob_off = i * (ecc->bytes + 4);
+               u8 *data = buf + data_off;
+               u8 *oob = chip->oob_poi + oob_off;
+
+               ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+                                                 oob_off + mtd->writesize,
+                                                 &cur_off, &max_bitflips);
                if (ret)
                        return ret;
        }
 
-       if (oob_required) {
-               cnt = ecc->layout->oobfree[i].length;
-               if (cnt > 0) {
-                       offset = mtd->writesize +
-                                ecc->layout->oobfree[i].offset;
-                       chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
-                       offset -= mtd->writesize;
-                       chip->write_buf(mtd, chip->oob_poi + offset, cnt);
-               }
+       if (oob_required)
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
+
+       sunxi_nfc_hw_ecc_disable(mtd);
+
+       return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
+                                      struct nand_chip *chip,
+                                      const uint8_t *buf, int oob_required,
+                                      int page)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int ret, i, cur_off = 0;
+
+       sunxi_nfc_hw_ecc_enable(mtd);
+
+       for (i = 0; i < ecc->steps; i++) {
+               int data_off = i * ecc->size;
+               int oob_off = i * (ecc->bytes + 4);
+               const u8 *data = buf + data_off;
+               const u8 *oob = chip->oob_poi + oob_off;
+
+               ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+                                                  oob_off + mtd->writesize,
+                                                  &cur_off);
+               if (ret)
+                       return ret;
        }
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~NFC_ECC_EN;
+       if (oob_required)
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
 
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_hw_ecc_disable(mtd);
 
        return 0;
 }
@@ -692,65 +786,29 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
                                               uint8_t *buf, int oob_required,
                                               int page)
 {
-       struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
-       struct sunxi_nand_hw_ecc *data = ecc->priv;
        unsigned int max_bitflips = 0;
-       uint8_t *oob = chip->oob_poi;
-       int offset = 0;
-       int ret;
-       int cnt;
-       u32 tmp;
-       int i;
+       int ret, i, cur_off = 0;
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
-       tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
-              NFC_ECC_EXCEPTION;
-
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_hw_ecc_enable(mtd);
 
        for (i = 0; i < ecc->steps; i++) {
-               chip->read_buf(mtd, NULL, ecc->size);
-
-               tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
-               writel(tmp, nfc->regs + NFC_REG_CMD);
-
-               ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+               int data_off = i * (ecc->size + ecc->bytes + 4);
+               int oob_off = data_off + ecc->size;
+               u8 *data = buf + (i * ecc->size);
+               u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+
+               ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+                                                 oob_off, &cur_off,
+                                                 &max_bitflips);
                if (ret)
                        return ret;
-
-               memcpy_fromio(buf, nfc->regs + NFC_RAM0_BASE, ecc->size);
-               buf += ecc->size;
-               offset += ecc->size;
-
-               if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
-                       mtd->ecc_stats.failed++;
-               } else {
-                       tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff;
-                       mtd->ecc_stats.corrected += tmp;
-                       max_bitflips = max_t(unsigned int, max_bitflips, tmp);
-               }
-
-               if (oob_required) {
-                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
-                       chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
-                       oob += ecc->bytes + ecc->prepad;
-               }
-
-               offset += ecc->bytes + ecc->prepad;
        }
 
-       if (oob_required) {
-               cnt = mtd->oobsize - (oob - chip->oob_poi);
-               if (cnt > 0) {
-                       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
-                       chip->read_buf(mtd, oob, cnt);
-               }
-       }
+       if (oob_required)
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
 
-       writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
-              nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_hw_ecc_disable(mtd);
 
        return max_bitflips;
 }
@@ -758,57 +816,29 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
 static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
                                                struct nand_chip *chip,
                                                const uint8_t *buf,
-                                               int oob_required)
+                                               int oob_required, int page)
 {
-       struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
-       struct sunxi_nand_hw_ecc *data = ecc->priv;
-       uint8_t *oob = chip->oob_poi;
-       int offset = 0;
-       int ret;
-       int cnt;
-       u32 tmp;
-       int i;
+       int ret, i, cur_off = 0;
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
-       tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
-              NFC_ECC_EXCEPTION;
-
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_hw_ecc_enable(mtd);
 
        for (i = 0; i < ecc->steps; i++) {
-               chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
-               offset += ecc->size;
-
-               /* Fill OOB data in */
-               writel(NFC_BUF_TO_USER_DATA(oob),
-                      nfc->regs + NFC_REG_USER_DATA_BASE);
+               int data_off = i * (ecc->size + ecc->bytes + 4);
+               int oob_off = data_off + ecc->size;
+               const u8 *data = buf + (i * ecc->size);
+               const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
 
-               tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
-                     (1 << 30);
-               writel(tmp, nfc->regs + NFC_REG_CMD);
-
-               ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+               ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
+                                                  oob, oob_off, &cur_off);
                if (ret)
                        return ret;
-
-               offset += ecc->bytes + ecc->prepad;
-               oob += ecc->bytes + ecc->prepad;
-       }
-
-       if (oob_required) {
-               cnt = mtd->oobsize - (oob - chip->oob_poi);
-               if (cnt > 0) {
-                       chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
-                       chip->write_buf(mtd, oob, cnt);
-               }
        }
 
-       tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
-       tmp &= ~NFC_ECC_EN;
+       if (oob_required)
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
 
-       writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+       sunxi_nfc_hw_ecc_disable(mtd);
 
        return 0;
 }
@@ -970,17 +1000,23 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
                mode = chip->nand.onfi_timing_mode_default;
        } else {
                uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
+               int i;
 
                mode = fls(mode) - 1;
                if (mode < 0)
                        mode = 0;
 
                feature[0] = mode;
-               ret = chip->nand.onfi_set_features(&chip->mtd, &chip->nand,
+               for (i = 0; i < chip->nsels; i++) {
+                       chip->nand.select_chip(&chip->mtd, i);
+                       ret = chip->nand.onfi_set_features(&chip->mtd,
+                                               &chip->nand,
                                                ONFI_FEATURE_ADDR_TIMING_MODE,
                                                feature);
-               if (ret)
-                       return ret;
+                       chip->nand.select_chip(&chip->mtd, -1);
+                       if (ret)
+                               return ret;
+               }
        }
 
        timings = onfi_async_timing_mode_to_sdr_timings(mode);
@@ -1154,16 +1190,9 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
                               struct device_node *np)
 {
        struct nand_chip *nand = mtd->priv;
-       int strength;
-       int blk_size;
        int ret;
 
-       blk_size = of_get_nand_ecc_step_size(np);
-       strength = of_get_nand_ecc_strength(np);
-       if (blk_size > 0 && strength > 0) {
-               ecc->size = blk_size;
-               ecc->strength = strength;
-       } else {
+       if (!ecc->size) {
                ecc->size = nand->ecc_step_ds;
                ecc->strength = nand->ecc_strength_ds;
        }
@@ -1171,12 +1200,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
        if (!ecc->size || !ecc->strength)
                return -EINVAL;
 
-       ecc->mode = NAND_ECC_HW;
-
-       ret = of_get_nand_ecc_mode(np);
-       if (ret >= 0)
-               ecc->mode = ret;
-
        switch (ecc->mode) {
        case NAND_ECC_SOFT_BCH:
                break;
@@ -1302,24 +1325,29 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
        nand->chip_delay = 200;
        nand->controller = &nfc->controller;
+       /*
+        * Set the ECC mode to the default value in case nothing is specified
+        * in the DT.
+        */
+       nand->ecc.mode = NAND_ECC_HW;
+       nand->flash_node = np;
        nand->select_chip = sunxi_nfc_select_chip;
        nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
        nand->read_buf = sunxi_nfc_read_buf;
        nand->write_buf = sunxi_nfc_write_buf;
        nand->read_byte = sunxi_nfc_read_byte;
 
-       if (of_get_nand_on_flash_bbt(np))
-               nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-
        mtd = &chip->mtd;
        mtd->dev.parent = dev;
        mtd->priv = nand;
-       mtd->owner = THIS_MODULE;
 
        ret = nand_scan_ident(mtd, nsels, NULL);
        if (ret)
                return ret;
 
+       if (nand->bbt_options & NAND_BBT_USE_FLASH)
+               nand->bbt_options |= NAND_BBT_NO_OOB;
+
        ret = sunxi_nand_chip_init_timings(chip, np);
        if (ret) {
                dev_err(dev, "could not configure chip timings: %d\n", ret);
index fb8fd35fa668516dcb763037e164691482eca9ea..befddf0776e4c2d03cfcb674735c7d9a9b24674c 100644 (file)
@@ -382,6 +382,7 @@ static int tmio_probe(struct platform_device *dev)
        nand_chip = &tmio->chip;
        mtd->priv = nand_chip;
        mtd->name = "tmio-nand";
+       mtd->dev.parent = &dev->dev;
 
        tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
        if (!tmio->ccr)
index 9c0bc45e28a955f83699a28ff232e8060015405c..8572519b8441b98fa94d55dda5b6d9c35bece1ea 100644 (file)
@@ -323,7 +323,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                        continue;
                chip = &txx9_priv->chip;
                mtd = &txx9_priv->mtd;
-               mtd->owner = THIS_MODULE;
+               mtd->dev.parent = &dev->dev;
 
                mtd->priv = chip;
 
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
new file mode 100644 (file)
index 0000000..8805d63
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
+ *
+ * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
+ * Jason ported to M54418TWR and MVFA5 (VF610).
+ * Authors: Stefan Agner <stefan.agner@toradex.com>
+ *          Bill Pringlemeir <bpringlemeir@nbsps.com>
+ *          Shaohui Xie <b21989@freescale.com>
+ *          Jason Jin <Jason.jin@freescale.com>
+ *
+ * Based on original driver mpc5121_nfc.c.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Limitations:
+ * - Untested on MPC5125 and M54418.
+ * - DMA and pipelining not used.
+ * - 2K pages or less.
+ * - HW ECC: Only 2K page with 64+ OOB.
+ * - HW ECC: Only 24 and 32-bit error correction implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define        DRV_NAME                "vf610_nfc"
+
+/* Register Offsets */
+#define NFC_FLASH_CMD1                 0x3F00
+#define NFC_FLASH_CMD2                 0x3F04
+#define NFC_COL_ADDR                   0x3F08
+#define NFC_ROW_ADDR                   0x3F0c
+#define NFC_ROW_ADDR_INC               0x3F14
+#define NFC_FLASH_STATUS1              0x3F18
+#define NFC_FLASH_STATUS2              0x3F1c
+#define NFC_CACHE_SWAP                 0x3F28
+#define NFC_SECTOR_SIZE                        0x3F2c
+#define NFC_FLASH_CONFIG               0x3F30
+#define NFC_IRQ_STATUS                 0x3F38
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)               ((n) *  0x1000)
+
+#define PAGE_2K                                0x0800
+#define OOB_64                         0x0040
+#define OOB_MAX                                0x0100
+
+/*
+ * NFC_CMD2[CODE] values. See section:
+ *  - 31.4.7 Flash Command Code Description, Vybrid manual
+ *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
+ *
+ * Briefly these are bitmasks of controller cycles.
+ */
+#define READ_PAGE_CMD_CODE             0x7EE0
+#define READ_ONFI_PARAM_CMD_CODE       0x4860
+#define PROGRAM_PAGE_CMD_CODE          0x7FC0
+#define ERASE_CMD_CODE                 0x4EC0
+#define READ_ID_CMD_CODE               0x4804
+#define RESET_CMD_CODE                 0x4040
+#define STATUS_READ_CMD_CODE           0x4068
+
+/* NFC ECC mode define */
+#define ECC_BYPASS                     0
+#define ECC_45_BYTE                    6
+#define ECC_60_BYTE                    7
+
+/*** Register Mask and bit definitions */
+
+/* NFC_FLASH_CMD1 Field */
+#define CMD_BYTE2_MASK                         0xFF000000
+#define CMD_BYTE2_SHIFT                                24
+
+/* NFC_FLASH_CM2 Field */
+#define CMD_BYTE1_MASK                         0xFF000000
+#define CMD_BYTE1_SHIFT                                24
+#define CMD_CODE_MASK                          0x00FFFF00
+#define CMD_CODE_SHIFT                         8
+#define BUFNO_MASK                             0x00000006
+#define BUFNO_SHIFT                            1
+#define START_BIT                              BIT(0)
+
+/* NFC_COL_ADDR Field */
+#define COL_ADDR_MASK                          0x0000FFFF
+#define COL_ADDR_SHIFT                         0
+
+/* NFC_ROW_ADDR Field */
+#define ROW_ADDR_MASK                          0x00FFFFFF
+#define ROW_ADDR_SHIFT                         0
+#define ROW_ADDR_CHIP_SEL_RB_MASK              0xF0000000
+#define ROW_ADDR_CHIP_SEL_RB_SHIFT             28
+#define ROW_ADDR_CHIP_SEL_MASK                 0x0F000000
+#define ROW_ADDR_CHIP_SEL_SHIFT                        24
+
+/* NFC_FLASH_STATUS2 Field */
+#define STATUS_BYTE1_MASK                      0x000000FF
+
+/* NFC_FLASH_CONFIG Field */
+#define CONFIG_ECC_SRAM_ADDR_MASK              0x7FC00000
+#define CONFIG_ECC_SRAM_ADDR_SHIFT             22
+#define CONFIG_ECC_SRAM_REQ_BIT                        BIT(21)
+#define CONFIG_DMA_REQ_BIT                     BIT(20)
+#define CONFIG_ECC_MODE_MASK                   0x000E0000
+#define CONFIG_ECC_MODE_SHIFT                  17
+#define CONFIG_FAST_FLASH_BIT                  BIT(16)
+#define CONFIG_16BIT                           BIT(7)
+#define CONFIG_BOOT_MODE_BIT                   BIT(6)
+#define CONFIG_ADDR_AUTO_INCR_BIT              BIT(5)
+#define CONFIG_BUFNO_AUTO_INCR_BIT             BIT(4)
+#define CONFIG_PAGE_CNT_MASK                   0xF
+#define CONFIG_PAGE_CNT_SHIFT                  0
+
+/* NFC_IRQ_STATUS Field */
+#define IDLE_IRQ_BIT                           BIT(29)
+#define IDLE_EN_BIT                            BIT(20)
+#define CMD_DONE_CLEAR_BIT                     BIT(18)
+#define IDLE_CLEAR_BIT                         BIT(17)
+
+/*
+ * ECC status - seems to consume 8 bytes (double word). The documented
+ * status byte is located in the lowest byte of the second word (which is
+ * the 4th or 7th byte depending on endianness).
+ * Calculate an offset to store the ECC status at the end of the buffer.
+ */
+#define ECC_SRAM_ADDR          (PAGE_2K + OOB_MAX - 8)
+
+#define ECC_STATUS             0x4
+#define ECC_STATUS_MASK                0x80
+#define ECC_STATUS_ERR_COUNT   0x3F
+
+enum vf610_nfc_alt_buf {
+       ALT_BUF_DATA = 0,
+       ALT_BUF_ID = 1,
+       ALT_BUF_STAT = 2,
+       ALT_BUF_ONFI = 3,
+};
+
+enum vf610_nfc_variant {
+       NFC_VFC610 = 1,
+};
+
+struct vf610_nfc {
+       struct mtd_info mtd;
+       struct nand_chip chip;
+       struct device *dev;
+       void __iomem *regs;
+       struct completion cmd_done;
+       uint buf_offset;
+       int write_sz;
+       /* Status and ID are in alternate locations. */
+       enum vf610_nfc_alt_buf alt_buf;
+       enum vf610_nfc_variant variant;
+       struct clk *clk;
+       bool use_hw_ecc;
+       u32 ecc_mode;
+};
+
+#define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd)
+
+static struct nand_ecclayout vf610_nfc_ecc45 = {
+       .eccbytes = 45,
+       .eccpos = {19, 20, 21, 22, 23,
+                  24, 25, 26, 27, 28, 29, 30, 31,
+                  32, 33, 34, 35, 36, 37, 38, 39,
+                  40, 41, 42, 43, 44, 45, 46, 47,
+                  48, 49, 50, 51, 52, 53, 54, 55,
+                  56, 57, 58, 59, 60, 61, 62, 63},
+       .oobfree = {
+               {.offset = 2,
+                .length = 17} }
+};
+
+static struct nand_ecclayout vf610_nfc_ecc60 = {
+       .eccbytes = 60,
+       .eccpos = { 4,  5,  6,  7,  8,  9, 10, 11,
+                  12, 13, 14, 15, 16, 17, 18, 19,
+                  20, 21, 22, 23, 24, 25, 26, 27,
+                  28, 29, 30, 31, 32, 33, 34, 35,
+                  36, 37, 38, 39, 40, 41, 42, 43,
+                  44, 45, 46, 47, 48, 49, 50, 51,
+                  52, 53, 54, 55, 56, 57, 58, 59,
+                  60, 61, 62, 63 },
+       .oobfree = {
+               {.offset = 2,
+                .length = 2} }
+};
+
+static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
+{
+       return readl(nfc->regs + reg);
+}
+
+static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
+{
+       writel(val, nfc->regs + reg);
+}
+
+static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+       vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
+}
+
+static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+       vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
+}
+
+static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
+                                      u32 mask, u32 shift, u32 val)
+{
+       vf610_nfc_write(nfc, reg,
+                       (vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
+}
+
+static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
+                                   size_t n)
+{
+       /*
+        * Use this accessor for the internal SRAM buffers. On the ARM
+        * Freescale Vybrid SoC it's known that the driver can treat
+        * the SRAM buffer as if it's memory. Other platform might need
+        * to treat the buffers differently.
+        *
+        * For the time being, use memcpy
+        */
+       memcpy(dst, src, n);
+}
+
+/* Clear flags for upcoming command */
+static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
+{
+       u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
+
+       tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
+       vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
+}
+
+static void vf610_nfc_done(struct vf610_nfc *nfc)
+{
+       unsigned long timeout = msecs_to_jiffies(100);
+
+       /*
+        * Barrier is needed after this write. This write need
+        * to be done before reading the next register the first
+        * time.
+        * vf610_nfc_set implicates such a barrier by using writel
+        * to write to the register.
+        */
+       vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+       vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
+
+       if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
+               dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
+
+       vf610_nfc_clear_status(nfc);
+}
+
+static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
+{
+       u32 flash_id;
+
+       if (col < 4) {
+               flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
+               flash_id >>= (3 - col) * 8;
+       } else {
+               flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
+               flash_id >>= 24;
+       }
+
+       return flash_id & 0xff;
+}
+
+static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
+{
+       return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
+}
+
+static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
+                                  u32 cmd_code)
+{
+       u32 tmp;
+
+       vf610_nfc_clear_status(nfc);
+
+       tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
+       tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
+       tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
+       tmp |= cmd_code << CMD_CODE_SHIFT;
+       vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
+}
+
+static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
+                                   u32 cmd_byte2, u32 cmd_code)
+{
+       u32 tmp;
+
+       vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
+
+       tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
+       tmp &= ~CMD_BYTE2_MASK;
+       tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
+       vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
+}
+
+static irqreturn_t vf610_nfc_irq(int irq, void *data)
+{
+       struct mtd_info *mtd = data;
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+       complete(&nfc->cmd_done);
+
+       return IRQ_HANDLED;
+}
+
+static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
+{
+       if (column != -1) {
+               if (nfc->chip.options & NAND_BUSWIDTH_16)
+                       column = column / 2;
+               vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
+                                   COL_ADDR_SHIFT, column);
+       }
+       if (page != -1)
+               vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
+                                   ROW_ADDR_SHIFT, page);
+}
+
+static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
+{
+       vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+                           CONFIG_ECC_MODE_MASK,
+                           CONFIG_ECC_MODE_SHIFT, ecc_mode);
+}
+
+static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
+{
+       vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
+}
+
+static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
+                             int column, int page)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
+
+       nfc->buf_offset = max(column, 0);
+       nfc->alt_buf = ALT_BUF_DATA;
+
+       switch (command) {
+       case NAND_CMD_SEQIN:
+               /* Use valid column/page from preread... */
+               vf610_nfc_addr_cycle(nfc, column, page);
+               nfc->buf_offset = 0;
+
+               /*
+                * SEQIN => data => PAGEPROG sequence is done by the controller
+                * hence we do not need to issue the command here...
+                */
+               return;
+       case NAND_CMD_PAGEPROG:
+               trfr_sz += nfc->write_sz;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
+                                       command, PROGRAM_PAGE_CMD_CODE);
+               if (nfc->use_hw_ecc)
+                       vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+               else
+                       vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_RESET:
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
+               break;
+
+       case NAND_CMD_READOOB:
+               trfr_sz += mtd->oobsize;
+               column = mtd->writesize;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+                                       NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_READ0:
+               trfr_sz += mtd->writesize + mtd->oobsize;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+                                       NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+               break;
+
+       case NAND_CMD_PARAM:
+               nfc->alt_buf = ALT_BUF_ONFI;
+               trfr_sz = 3 * sizeof(struct nand_onfi_params);
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, -1, column);
+               vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_ERASE1:
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_commands(nfc, command,
+                                       NAND_CMD_ERASE2, ERASE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               break;
+
+       case NAND_CMD_READID:
+               nfc->alt_buf = ALT_BUF_ID;
+               nfc->buf_offset = 0;
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, -1, column);
+               break;
+
+       case NAND_CMD_STATUS:
+               nfc->alt_buf = ALT_BUF_STAT;
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
+               break;
+       default:
+               return;
+       }
+
+       vf610_nfc_done(nfc);
+
+       nfc->use_hw_ecc = false;
+       nfc->write_sz = 0;
+}
+
+static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       uint c = nfc->buf_offset;
+
+       /* Alternate buffers are only supported through read_byte */
+       WARN_ON(nfc->alt_buf);
+
+       vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
+
+       nfc->buf_offset += len;
+}
+
+static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+                               int len)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       uint c = nfc->buf_offset;
+       uint l;
+
+       l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
+       vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
+
+       nfc->write_sz += l;
+       nfc->buf_offset += l;
+}
+
+static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u8 tmp;
+       uint c = nfc->buf_offset;
+
+       switch (nfc->alt_buf) {
+       case ALT_BUF_ID:
+               tmp = vf610_nfc_get_id(nfc, c);
+               break;
+       case ALT_BUF_STAT:
+               tmp = vf610_nfc_get_status(nfc);
+               break;
+#ifdef __LITTLE_ENDIAN
+       case ALT_BUF_ONFI:
+               /* Reverse byte since the controller uses big endianness */
+               c = nfc->buf_offset ^ 0x3;
+               /* fall-through */
+#endif
+       default:
+               tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+               break;
+       }
+       nfc->buf_offset++;
+       return tmp;
+}
+
+static u16 vf610_nfc_read_word(struct mtd_info *mtd)
+{
+       u16 tmp;
+
+       vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+       return tmp;
+}
+
+/* If not provided, upper layers apply a fixed delay. */
+static int vf610_nfc_dev_ready(struct mtd_info *mtd)
+{
+       /* NFC handles R/B internally; always ready.  */
+       return 1;
+}
+
+/*
+ * This function supports Vybrid only (MPC5125 would have full RB and four CS)
+ */
+static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
+
+       /* Vybrid only (MPC5125 would have full RB and four CS) */
+       if (nfc->variant != NFC_VFC610)
+               return;
+
+       tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
+
+       if (chip >= 0) {
+               tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
+               tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+       }
+
+       vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
+}
+
+/* Count the number of 0's in buff up to max_bits */
+static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+       uint32_t *buff32 = (uint32_t *)buff;
+       int k, written_bits = 0;
+
+       for (k = 0; k < (size / 4); k++) {
+               written_bits += hweight32(~buff32[k]);
+               if (unlikely(written_bits > max_bits))
+                       break;
+       }
+
+       return written_bits;
+}
+
+static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+                                        uint8_t *oob, int page)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
+       u8 ecc_status;
+       u8 ecc_count;
+       int flips_threshold = nfc->chip.ecc.strength / 2;
+
+       ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
+       ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
+
+       if (!(ecc_status & ECC_STATUS_MASK))
+               return ecc_count;
+
+       /* Read OOB without ECC unit enabled */
+       vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
+       vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
+
+       /*
+        * On an erased page, bit count (including OOB) should be zero or
+        * at least less then half of the ECC strength.
+        */
+       return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
+                                          mtd->oobsize, NULL, 0,
+                                          flips_threshold);
+}
+
+static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
+{
+       int eccsize = chip->ecc.size;
+       int stat;
+
+       vf610_nfc_read_buf(mtd, buf, eccsize);
+       if (oob_required)
+               vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
+
+       if (stat < 0) {
+               mtd->ecc_stats.failed++;
+               return 0;
+       } else {
+               mtd->ecc_stats.corrected += stat;
+               return stat;
+       }
+}
+
+static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf, int oob_required, int page)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       vf610_nfc_write_buf(mtd, buf, mtd->writesize);
+       if (oob_required)
+               vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       /* Always write whole page including OOB due to HW ECC */
+       nfc->use_hw_ecc = true;
+       nfc->write_sz = mtd->writesize + mtd->oobsize;
+
+       return 0;
+}
+
+static const struct of_device_id vf610_nfc_dt_ids[] = {
+       { .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
+
+static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
+{
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
+       vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
+
+       /* Disable virtual pages, only one elementary transfer unit */
+       vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
+                           CONFIG_PAGE_CNT_SHIFT, 1);
+}
+
+static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
+{
+       if (nfc->chip.options & NAND_BUSWIDTH_16)
+               vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+       else
+               vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+
+       if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+               /* Set ECC status offset in SRAM */
+               vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+                                   CONFIG_ECC_SRAM_ADDR_MASK,
+                                   CONFIG_ECC_SRAM_ADDR_SHIFT,
+                                   ECC_SRAM_ADDR >> 3);
+
+               /* Enable ECC status in SRAM */
+               vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
+       }
+}
+
+static int vf610_nfc_probe(struct platform_device *pdev)
+{
+       struct vf610_nfc *nfc;
+       struct resource *res;
+       struct mtd_info *mtd;
+       struct nand_chip *chip;
+       struct device_node *child;
+       const struct of_device_id *of_id;
+       int err;
+       int irq;
+
+       nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       nfc->dev = &pdev->dev;
+       mtd = &nfc->mtd;
+       chip = &nfc->chip;
+
+       mtd->priv = chip;
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = nfc->dev;
+       mtd->name = DRV_NAME;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->regs = devm_ioremap_resource(nfc->dev, res);
+       if (IS_ERR(nfc->regs))
+               return PTR_ERR(nfc->regs);
+
+       nfc->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(nfc->clk))
+               return PTR_ERR(nfc->clk);
+
+       err = clk_prepare_enable(nfc->clk);
+       if (err) {
+               dev_err(nfc->dev, "Unable to enable clock!\n");
+               return err;
+       }
+
+       of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
+       nfc->variant = (enum vf610_nfc_variant)of_id->data;
+
+       for_each_available_child_of_node(nfc->dev->of_node, child) {
+               if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
+
+                       if (chip->flash_node) {
+                               dev_err(nfc->dev,
+                                       "Only one NAND chip supported!\n");
+                               err = -EINVAL;
+                               goto error;
+                       }
+
+                       chip->flash_node = child;
+               }
+       }
+
+       if (!chip->flash_node) {
+               dev_err(nfc->dev, "NAND chip sub-node missing!\n");
+               err = -ENODEV;
+               goto err_clk;
+       }
+
+       chip->dev_ready = vf610_nfc_dev_ready;
+       chip->cmdfunc = vf610_nfc_command;
+       chip->read_byte = vf610_nfc_read_byte;
+       chip->read_word = vf610_nfc_read_word;
+       chip->read_buf = vf610_nfc_read_buf;
+       chip->write_buf = vf610_nfc_write_buf;
+       chip->select_chip = vf610_nfc_select_chip;
+
+       chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+       init_completion(&nfc->cmd_done);
+
+       err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
+       if (err) {
+               dev_err(nfc->dev, "Error requesting IRQ!\n");
+               goto error;
+       }
+
+       vf610_nfc_preinit_controller(nfc);
+
+       /* first scan to find the device and get the page size */
+       if (nand_scan_ident(mtd, 1, NULL)) {
+               err = -ENXIO;
+               goto error;
+       }
+
+       vf610_nfc_init_controller(nfc);
+
+       /* Bad block options. */
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+       /* Single buffer only, max 256 OOB minus ECC status */
+       if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+               dev_err(nfc->dev, "Unsupported flash page size\n");
+               err = -ENXIO;
+               goto error;
+       }
+
+       if (chip->ecc.mode == NAND_ECC_HW) {
+               if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+                       dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               if (chip->ecc.size != mtd->writesize) {
+                       dev_err(nfc->dev, "Step size needs to be page size\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               /* Only 64 byte ECC layouts known */
+               if (mtd->oobsize > 64)
+                       mtd->oobsize = 64;
+
+               if (chip->ecc.strength == 32) {
+                       nfc->ecc_mode = ECC_60_BYTE;
+                       chip->ecc.bytes = 60;
+                       chip->ecc.layout = &vf610_nfc_ecc60;
+               } else if (chip->ecc.strength == 24) {
+                       nfc->ecc_mode = ECC_45_BYTE;
+                       chip->ecc.bytes = 45;
+                       chip->ecc.layout = &vf610_nfc_ecc45;
+               } else {
+                       dev_err(nfc->dev, "Unsupported ECC strength\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               /* propagate ecc.layout to mtd_info */
+               mtd->ecclayout = chip->ecc.layout;
+               chip->ecc.read_page = vf610_nfc_read_page;
+               chip->ecc.write_page = vf610_nfc_write_page;
+
+               chip->ecc.size = PAGE_2K;
+       }
+
+       /* second phase scan */
+       if (nand_scan_tail(mtd)) {
+               err = -ENXIO;
+               goto error;
+       }
+
+       platform_set_drvdata(pdev, mtd);
+
+       /* Register device in MTD */
+       return mtd_device_parse_register(mtd, NULL,
+               &(struct mtd_part_parser_data){
+                       .of_node = chip->flash_node,
+               },
+               NULL, 0);
+
+error:
+       of_node_put(chip->flash_node);
+err_clk:
+       clk_disable_unprepare(nfc->clk);
+       return err;
+}
+
+static int vf610_nfc_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       nand_release(mtd);
+       clk_disable_unprepare(nfc->clk);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vf610_nfc_suspend(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       clk_disable_unprepare(nfc->clk);
+       return 0;
+}
+
+static int vf610_nfc_resume(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       pinctrl_pm_select_default_state(dev);
+
+       clk_prepare_enable(nfc->clk);
+
+       vf610_nfc_preinit_controller(nfc);
+       vf610_nfc_init_controller(nfc);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
+
+static struct platform_driver vf610_nfc_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .of_match_table = vf610_nfc_dt_ids,
+               .pm     = &vf610_nfc_pm_ops,
+       },
+       .probe          = vf610_nfc_probe,
+       .remove         = vf610_nfc_remove,
+};
+
+module_platform_driver(vf610_nfc_driver);
+
+MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
+MODULE_LICENSE("GPL");
index aa26c32e1bc28943426992eba09fddc207cf104d..669c3452f278fb0e365570872893855c9ce21e2c 100644 (file)
@@ -29,23 +29,33 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                                   struct mtd_partition **pparts,
                                   struct mtd_part_parser_data *data)
 {
-       struct device_node *node;
+       struct device_node *mtd_node;
+       struct device_node *ofpart_node;
        const char *partname;
        struct device_node *pp;
-       int nr_parts, i;
+       int nr_parts, i, ret = 0;
+       bool dedicated = true;
 
 
        if (!data)
                return 0;
 
-       node = data->of_node;
-       if (!node)
+       mtd_node = data->of_node;
+       if (!mtd_node)
                return 0;
 
+       ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+       if (!ofpart_node) {
+               pr_warn("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
+                       master->name, mtd_node->full_name);
+               ofpart_node = mtd_node;
+               dedicated = false;
+       }
+
        /* First count the subnodes */
        nr_parts = 0;
-       for_each_child_of_node(node,  pp) {
-               if (node_has_compatible(pp))
+       for_each_child_of_node(ofpart_node,  pp) {
+               if (!dedicated && node_has_compatible(pp))
                        continue;
 
                nr_parts++;
@@ -59,22 +69,36 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                return -ENOMEM;
 
        i = 0;
-       for_each_child_of_node(node,  pp) {
+       for_each_child_of_node(ofpart_node,  pp) {
                const __be32 *reg;
                int len;
                int a_cells, s_cells;
 
-               if (node_has_compatible(pp))
+               if (!dedicated && node_has_compatible(pp))
                        continue;
 
                reg = of_get_property(pp, "reg", &len);
                if (!reg) {
-                       nr_parts--;
-                       continue;
+                       if (dedicated) {
+                               pr_debug("%s: ofpart partition %s (%s) missing reg property.\n",
+                                        master->name, pp->full_name,
+                                        mtd_node->full_name);
+                               goto ofpart_fail;
+                       } else {
+                               nr_parts--;
+                               continue;
+                       }
                }
 
                a_cells = of_n_addr_cells(pp);
                s_cells = of_n_size_cells(pp);
+               if (len / 4 != a_cells + s_cells) {
+                       pr_debug("%s: ofpart partition %s (%s) error parsing reg property.\n",
+                                master->name, pp->full_name,
+                                mtd_node->full_name);
+                       goto ofpart_fail;
+               }
+
                (*pparts)[i].offset = of_read_number(reg, a_cells);
                (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
 
@@ -92,15 +116,20 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                i++;
        }
 
-       if (!i) {
-               of_node_put(pp);
-               pr_err("No valid partition found on %s\n", node->full_name);
-               kfree(*pparts);
-               *pparts = NULL;
-               return -EINVAL;
-       }
+       if (!nr_parts)
+               goto ofpart_none;
 
        return nr_parts;
+
+ofpart_fail:
+       pr_err("%s: error parsing ofpart partition %s (%s)\n",
+              master->name, pp->full_name, mtd_node->full_name);
+       ret = -EINVAL;
+ofpart_none:
+       of_node_put(pp);
+       kfree(*pparts);
+       *pparts = NULL;
+       return ret;
 }
 
 static struct mtd_part_parser ofpart_parser = {
index ab7bda0bb245ce4e702f87ebf5136f09920fbf1d..125da34d8ff95746922c5741ed358554b06d9c5d 100644 (file)
@@ -60,9 +60,8 @@ static int generic_onenand_probe(struct platform_device *pdev)
        info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
        info->onenand.irq = platform_get_irq(pdev, 0);
 
-       info->mtd.name = dev_name(&pdev->dev);
+       info->mtd.dev.parent = &pdev->dev;
        info->mtd.priv = &info->onenand;
-       info->mtd.owner = THIS_MODULE;
 
        if (onenand_scan(&info->mtd, 1)) {
                err = -ENXIO;
index 646ddd6db1b4a24ccd6178f1cad8ff382709de24..3e02856962279485025e5c54f2d2ff4aa05f9f04 100644 (file)
@@ -710,9 +710,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
                 c->onenand.base, c->freq);
 
        c->pdev = pdev;
-       c->mtd.name = dev_name(&pdev->dev);
        c->mtd.priv = &c->onenand;
-       c->mtd.owner = THIS_MODULE;
 
        c->mtd.dev.parent = &pdev->dev;
 
index 739259513055567114aa26649f74ef6b7d7a58c9..af0ac1a7bf8f5518ab180034f3c1eaa514bcc030 100644 (file)
@@ -864,7 +864,6 @@ static int s3c_onenand_probe(struct platform_device *pdev)
        this = (struct onenand_chip *) &mtd[1];
        mtd->priv = this;
        mtd->dev.parent = &pdev->dev;
-       mtd->owner = THIS_MODULE;
        onenand->pdev = pdev;
        onenand->type = platform_get_device_id(pdev)->driver_data;
 
index 89bf4c1faa2b3547aaeb61bf58ec2224524f55ee..2fe2a7e90fa9f2b4b8b2bb4b1cfe2761ff96591f 100644 (file)
@@ -23,7 +23,8 @@ config MTD_SPI_NOR_USE_4K_SECTORS
 
 config SPI_FSL_QUADSPI
        tristate "Freescale Quad SPI controller"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables support for the Quad SPI controller in master mode.
          This controller does not support generic SPI. It only supports
index d32b7e04cccab780fcee0b0a3d84319b083f713b..7b10ed413983aecbc2b51a30b6bcdd1d98a1fa85 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mtd/spi-nor.h>
 #include <linux/mutex.h>
 #include <linux/pm_qos.h>
+#include <linux/sizes.h>
 
 /* Controller needs driver to swap endian */
 #define QUADSPI_QUIRK_SWAP_ENDIAN      (1 << 0)
 #define LUT_MODE               4
 #define LUT_MODE2              5
 #define LUT_MODE4              6
-#define LUT_READ               7
-#define LUT_WRITE              8
+#define LUT_FSL_READ           7
+#define LUT_FSL_WRITE          8
 #define LUT_JMP_ON_CS          9
 #define LUT_ADDR_DDR           10
 #define LUT_MODE_DDR           11
 #define LUT_MODE2_DDR          12
 #define LUT_MODE4_DDR          13
-#define LUT_READ_DDR           14
-#define LUT_WRITE_DDR          15
+#define LUT_FSL_READ_DDR               14
+#define LUT_FSL_WRITE_DDR              15
 #define LUT_DATA_LEARN         16
 
 /*
@@ -259,7 +260,6 @@ static struct fsl_qspi_devtype_data imx6ul_data = {
 
 #define FSL_QSPI_MAX_CHIP      4
 struct fsl_qspi {
-       struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
        struct spi_nor nor[FSL_QSPI_MAX_CHIP];
        void __iomem *iobase;
        void __iomem *ahb_addr;
@@ -366,7 +366,7 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
 
        writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
+       writel(LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
                        base + QUADSPI_LUT(lut_base + 1));
 
        /* Write enable */
@@ -387,11 +387,11 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
 
        writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
                        base + QUADSPI_LUT(lut_base));
-       writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
+       writel(LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
 
        /* Read Status */
        lut_base = SEQID_RDSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1),
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Erase a sector */
@@ -410,17 +410,17 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
 
        /* READ ID */
        lut_base = SEQID_RDID * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8),
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write Register */
        lut_base = SEQID_WRSR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2),
+       writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2),
                        base + QUADSPI_LUT(lut_base));
 
        /* Read Configuration Register */
        lut_base = SEQID_RDCR * 4;
-       writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1),
+       writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1),
                        base + QUADSPI_LUT(lut_base));
 
        /* Write disable */
@@ -798,8 +798,7 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return 0;
 }
 
-static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int write_enable)
+static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct fsl_qspi *q = nor->priv;
        int ret;
@@ -870,7 +869,7 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
                }
        }
 
-       dev_dbg(q->dev, "cmd [%x],read from 0x%p, len:%d\n",
+       dev_dbg(q->dev, "cmd [%x],read from %p, len:%zd\n",
                cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
                len);
 
@@ -888,7 +887,7 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
        int ret;
 
        dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
-               nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
+               nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs);
 
        ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
        if (ret)
@@ -1006,19 +1005,16 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 
        /* iterate the subnodes. */
        for_each_available_child_of_node(dev->of_node, np) {
-               char modalias[40];
-
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
 
                nor = &q->nor[i];
-               mtd = &q->mtd[i];
+               mtd = &nor->mtd;
 
-               nor->mtd = mtd;
                nor->dev = dev;
+               nor->flash_node = np;
                nor->priv = q;
-               mtd->priv = nor;
 
                /* fill the hooks */
                nor->read_reg = fsl_qspi_read_reg;
@@ -1030,10 +1026,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
                nor->prepare = fsl_qspi_prep;
                nor->unprepare = fsl_qspi_unprep;
 
-               ret = of_modalias_node(np, modalias, sizeof(modalias));
-               if (ret < 0)
-                       goto mutex_failed;
-
                ret = of_property_read_u32(np, "spi-max-frequency",
                                &q->clk_rate);
                if (ret < 0)
@@ -1042,7 +1034,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
                /* set the chip address for READID */
                fsl_qspi_set_base_addr(q, nor);
 
-               ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
+               ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
                if (ret)
                        goto mutex_failed;
 
@@ -1087,7 +1079,7 @@ last_init_failed:
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
-               mtd_device_unregister(&q->mtd[i]);
+               mtd_device_unregister(&q->nor[i].mtd);
        }
 mutex_failed:
        mutex_destroy(&q->lock);
@@ -1107,7 +1099,7 @@ static int fsl_qspi_remove(struct platform_device *pdev)
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
-               mtd_device_unregister(&q->mtd[i]);
+               mtd_device_unregister(&q->nor[i].mtd);
        }
 
        /* disable the hardware */
index 9ad1dd0896c02344339a9456993cfee57a5236ce..9e82098ae644d0218458fe0ecd3a4985fe9e2237 100644 (file)
@@ -60,7 +60,6 @@ struct nxp_spifi {
        struct clk *clk_reg;
        void __iomem *io_base;
        void __iomem *flash_base;
-       struct mtd_info mtd;
        struct spi_nor nor;
        bool memory_mode;
        u32 mcmd;
@@ -150,8 +149,7 @@ static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return nxp_spifi_wait_for_cmd(spifi);
 }
 
-static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
-                              int len, int write_enable)
+static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct nxp_spifi *spifi = nor->priv;
        u32 cmd;
@@ -331,9 +329,8 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
        writel(ctrl, spifi->io_base + SPIFI_CTRL);
 
-       spifi->mtd.priv  = &spifi->nor;
-       spifi->nor.mtd   = &spifi->mtd;
        spifi->nor.dev   = spifi->dev;
+       spifi->nor.flash_node = np;
        spifi->nor.priv  = spifi;
        spifi->nor.read  = nxp_spifi_read;
        spifi->nor.write = nxp_spifi_write;
@@ -365,7 +362,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
        }
 
        ppdata.of_node = np;
-       ret = mtd_device_parse_register(&spifi->mtd, NULL, &ppdata, NULL, 0);
+       ret = mtd_device_parse_register(&spifi->nor.mtd, NULL, &ppdata, NULL, 0);
        if (ret) {
                dev_err(spifi->dev, "mtd device parse failed\n");
                return ret;
@@ -454,7 +451,7 @@ static int nxp_spifi_remove(struct platform_device *pdev)
 {
        struct nxp_spifi *spifi = platform_get_drvdata(pdev);
 
-       mtd_device_unregister(&spifi->mtd);
+       mtd_device_unregister(&spifi->nor.mtd);
        clk_disable_unprepare(spifi->clk_spifi);
        clk_disable_unprepare(spifi->clk_reg);
 
index f59aedfe1462a431018de993543c4abc69131eed..49883905a434b68b98af50e515a0356731c62fa6 100644 (file)
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/math64.h>
+#include <linux/sizes.h>
 
-#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
 
 /* Define max times to check status register before we give up. */
-#define        MAX_READY_WAIT_JIFFIES  (40 * HZ) /* M25P16 specs 40s max chip erase */
+
+/*
+ * For everything but full-chip erase; probably could be much smaller, but kept
+ * around for safety for now
+ */
+#define DEFAULT_READY_WAIT_JIFFIES             (40UL * HZ)
+
+/*
+ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
+ * for larger flash
+ */
+#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES      (40UL * HZ)
 
 #define SPI_NOR_MAX_ID_LEN     6
 
@@ -145,7 +156,7 @@ static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 static inline int write_sr(struct spi_nor *nor, u8 val)
 {
        nor->cmd_buf[0] = val;
-       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
 }
 
 /*
@@ -154,7 +165,7 @@ static inline int write_sr(struct spi_nor *nor, u8 val)
  */
 static inline int write_enable(struct spi_nor *nor)
 {
-       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
 }
 
 /*
@@ -162,7 +173,7 @@ static inline int write_enable(struct spi_nor *nor)
  */
 static inline int write_disable(struct spi_nor *nor)
 {
-       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
 }
 
 static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
@@ -179,16 +190,16 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
        u8 cmd;
 
        switch (JEDEC_MFR(info)) {
-       case CFI_MFR_ST: /* Micron, actually */
+       case SNOR_MFR_MICRON:
                /* Some Micron need WREN command; all will accept it */
                need_wren = true;
-       case CFI_MFR_MACRONIX:
-       case 0xEF /* winbond */:
+       case SNOR_MFR_MACRONIX:
+       case SNOR_MFR_WINBOND:
                if (need_wren)
                        write_enable(nor);
 
                cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
-               status = nor->write_reg(nor, cmd, NULL, 0, 0);
+               status = nor->write_reg(nor, cmd, NULL, 0);
                if (need_wren)
                        write_disable(nor);
 
@@ -196,7 +207,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
        default:
                /* Spansion style */
                nor->cmd_buf[0] = enable << 7;
-               return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
+               return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
        }
 }
 static inline int spi_nor_sr_ready(struct spi_nor *nor)
@@ -233,12 +244,13 @@ static int spi_nor_ready(struct spi_nor *nor)
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
  */
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
+                                               unsigned long timeout_jiffies)
 {
        unsigned long deadline;
        int timeout = 0, ret;
 
-       deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+       deadline = jiffies + timeout_jiffies;
 
        while (!timeout) {
                if (time_after_eq(jiffies, deadline))
@@ -258,6 +270,12 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
        return -ETIMEDOUT;
 }
 
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+       return spi_nor_wait_till_ready_with_timeout(nor,
+                                                   DEFAULT_READY_WAIT_JIFFIES);
+}
+
 /*
  * Erase the whole flash memory
  *
@@ -265,9 +283,9 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
  */
 static int erase_chip(struct spi_nor *nor)
 {
-       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
+       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
 
-       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
 }
 
 static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
@@ -321,6 +339,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 
        /* whole-chip erase? */
        if (len == mtd->size) {
+               unsigned long timeout;
+
                write_enable(nor);
 
                if (erase_chip(nor)) {
@@ -328,7 +348,16 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        goto erase_err;
                }
 
-               ret = spi_nor_wait_till_ready(nor);
+               /*
+                * Scale the timeout linearly with the size of the flash, with
+                * a minimum calibrated to an old 2MB flash. We could try to
+                * pull these from CFI/SFDP, but these values should be good
+                * enough for now.
+                */
+               timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+                             CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+                             (unsigned long)(mtd->size / SZ_2M));
+               ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
                if (ret)
                        goto erase_err;
 
@@ -371,72 +400,171 @@ erase_err:
        return ret;
 }
 
+static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+                                uint64_t *len)
+{
+       struct mtd_info *mtd = &nor->mtd;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       int shift = ffs(mask) - 1;
+       int pow;
+
+       if (!(sr & mask)) {
+               /* No protection */
+               *ofs = 0;
+               *len = 0;
+       } else {
+               pow = ((sr & mask) ^ mask) >> shift;
+               *len = mtd->size >> pow;
+               *ofs = mtd->size - *len;
+       }
+}
+
+/*
+ * Return 1 if the entire region is locked, 0 otherwise
+ */
+static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+                           u8 sr)
+{
+       loff_t lock_offs;
+       uint64_t lock_len;
+
+       stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
+
+       return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+}
+
+/*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+ * Supports only the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+ *   - TB: top/bottom protect - only handle TB=0 (top protect)
+ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
+ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
+ *  --------------------------------------------------------------------------
+ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
+ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
+ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
+ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
+ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
+ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
+ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
+ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *
+ * Returns negative on errors, 0 on success.
+ */
 static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-       struct mtd_info *mtd = nor->mtd;
-       uint32_t offset = ofs;
-       uint8_t status_old, status_new;
-       int ret = 0;
+       struct mtd_info *mtd = &nor->mtd;
+       u8 status_old, status_new;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 shift = ffs(mask) - 1, pow, val;
 
        status_old = read_sr(nor);
 
-       if (offset < mtd->size - (mtd->size / 2))
-               status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
-       else if (offset < mtd->size - (mtd->size / 4))
-               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
-       else if (offset < mtd->size - (mtd->size / 8))
-               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-       else if (offset < mtd->size - (mtd->size / 16))
-               status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
-       else if (offset < mtd->size - (mtd->size / 32))
-               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-       else if (offset < mtd->size - (mtd->size / 64))
-               status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
-       else
-               status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+       /* SPI NOR always locks to the end */
+       if (ofs + len != mtd->size) {
+               /* Does combined region extend to end? */
+               if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
+                                     status_old))
+                       return -EINVAL;
+               len = mtd->size - ofs;
+       }
+
+       /*
+        * Need smallest pow such that:
+        *
+        *   1 / (2^pow) <= (len / size)
+        *
+        * so (assuming power-of-2 size) we do:
+        *
+        *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+        */
+       pow = ilog2(mtd->size) - ilog2(len);
+       val = mask - (pow << shift);
+       if (val & ~mask)
+               return -EINVAL;
+       /* Don't "lock" with no region! */
+       if (!(val & mask))
+               return -EINVAL;
+
+       status_new = (status_old & ~mask) | val;
 
        /* Only modify protection if it will not unlock other areas */
-       if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) >
-                               (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
-               write_enable(nor);
-               ret = write_sr(nor, status_new);
-       }
+       if ((status_new & mask) <= (status_old & mask))
+               return -EINVAL;
 
-       return ret;
+       write_enable(nor);
+       return write_sr(nor, status_new);
 }
 
+/*
+ * Unlock a region of the flash. See stm_lock() for more info
+ *
+ * Returns negative on errors, 0 on success.
+ */
 static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-       struct mtd_info *mtd = nor->mtd;
-       uint32_t offset = ofs;
+       struct mtd_info *mtd = &nor->mtd;
        uint8_t status_old, status_new;
-       int ret = 0;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 shift = ffs(mask) - 1, pow, val;
 
        status_old = read_sr(nor);
 
-       if (offset+len > mtd->size - (mtd->size / 64))
-               status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0);
-       else if (offset+len > mtd->size - (mtd->size / 32))
-               status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
-       else if (offset+len > mtd->size - (mtd->size / 16))
-               status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
-       else if (offset+len > mtd->size - (mtd->size / 8))
-               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-       else if (offset+len > mtd->size - (mtd->size / 4))
-               status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
-       else if (offset+len > mtd->size - (mtd->size / 2))
-               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-       else
-               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+       /* Cannot unlock; would unlock larger region than requested */
+       if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize,
+                            mtd->erasesize))
+               return -EINVAL;
 
-       /* Only modify protection if it will not lock other areas */
-       if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) <
-                               (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
-               write_enable(nor);
-               ret = write_sr(nor, status_new);
+       /*
+        * Need largest pow such that:
+        *
+        *   1 / (2^pow) >= (len / size)
+        *
+        * so (assuming power-of-2 size) we do:
+        *
+        *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+        */
+       pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
+       if (ofs + len == mtd->size) {
+               val = 0; /* fully unlocked */
+       } else {
+               val = mask - (pow << shift);
+               /* Some power-of-two sizes are not supported */
+               if (val & ~mask)
+                       return -EINVAL;
        }
 
-       return ret;
+       status_new = (status_old & ~mask) | val;
+
+       /* Only modify protection if it will not lock other areas */
+       if ((status_new & mask) >= (status_old & mask))
+               return -EINVAL;
+
+       write_enable(nor);
+       return write_sr(nor, status_new);
+}
+
+/*
+ * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * more info.
+ *
+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * negative on errors.
+ */
+static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+       int status;
+
+       status = read_sr(nor);
+       if (status < 0)
+               return status;
+
+       return stm_is_locked_sr(nor, ofs, len, status);
 }
 
 static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
@@ -469,6 +597,21 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return ret;
 }
 
+static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       int ret;
+
+       ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
+       if (ret)
+               return ret;
+
+       ret = nor->flash_is_locked(nor, ofs, len);
+
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+       return ret;
+}
+
 /* Used when the "_ext_id" is two bytes at most */
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
                .id = {                                                 \
@@ -585,6 +728,7 @@ static const struct flash_info spi_nor_ids[] = {
 
        /* Micron */
        { "n25q032",     INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
+       { "n25q032a",    INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
        { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
        { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
@@ -618,12 +762,13 @@ static const struct flash_info spi_nor_ids[] = {
        { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
        { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
        { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
-       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+       { "s25fl004k",  INFO(0xef4013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
        { "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
        { "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
-       { "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K) },
+       { "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
 
        /* SST -- large erase sizes are "overlays", "sectors" are 4K */
        { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
@@ -635,6 +780,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
        { "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
        { "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K) },
+       { "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
        { "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
        { "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
 
@@ -683,10 +829,11 @@ static const struct flash_info spi_nor_ids[] = {
        { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
        { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
        { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-       { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
+       { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
-       { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
+       { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -868,8 +1015,7 @@ static int macronix_quad_enable(struct spi_nor *nor)
        val = read_sr(nor);
        write_enable(nor);
 
-       nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
-       nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+       write_sr(nor, val | SR_QUAD_EN_MX);
 
        if (spi_nor_wait_till_ready(nor))
                return 1;
@@ -894,7 +1040,7 @@ static int write_sr_cr(struct spi_nor *nor, u16 val)
        nor->cmd_buf[0] = val & 0xff;
        nor->cmd_buf[1] = (val >> 8);
 
-       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
 }
 
 static int spansion_quad_enable(struct spi_nor *nor)
@@ -936,7 +1082,7 @@ static int micron_quad_enable(struct spi_nor *nor)
 
        /* set EVCR, enable quad I/O */
        nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
+       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
        if (ret < 0) {
                dev_err(nor->dev, "error while writing EVCR register\n");
                return ret;
@@ -965,14 +1111,14 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
        int status;
 
        switch (JEDEC_MFR(info)) {
-       case CFI_MFR_MACRONIX:
+       case SNOR_MFR_MACRONIX:
                status = macronix_quad_enable(nor);
                if (status) {
                        dev_err(nor->dev, "Macronix quad-read not enabled\n");
                        return -EINVAL;
                }
                return status;
-       case CFI_MFR_ST:
+       case SNOR_MFR_MICRON:
                status = micron_quad_enable(nor);
                if (status) {
                        dev_err(nor->dev, "Micron quad-read not enabled\n");
@@ -1004,8 +1150,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 {
        const struct flash_info *info = NULL;
        struct device *dev = nor->dev;
-       struct mtd_info *mtd = nor->mtd;
-       struct device_node *np = dev->of_node;
+       struct mtd_info *mtd = &nor->mtd;
+       struct device_node *np = nor->flash_node;
        int ret;
        int i;
 
@@ -1048,19 +1194,21 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        mutex_init(&nor->lock);
 
        /*
-        * Atmel, SST and Intel/Numonyx serial nor tend to power
-        * up with the software protection bits set
+        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+        * with the software protection bits set
         */
 
-       if (JEDEC_MFR(info) == CFI_MFR_ATMEL ||
-           JEDEC_MFR(info) == CFI_MFR_INTEL ||
-           JEDEC_MFR(info) == CFI_MFR_SST) {
+       if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+           JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+           JEDEC_MFR(info) == SNOR_MFR_SST ||
+           JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
                write_enable(nor);
                write_sr(nor, 0);
        }
 
        if (!mtd->name)
                mtd->name = dev_name(dev);
+       mtd->priv = nor;
        mtd->type = MTD_NORFLASH;
        mtd->writesize = 1;
        mtd->flags = MTD_CAP_NORFLASH;
@@ -1068,15 +1216,18 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        mtd->_erase = spi_nor_erase;
        mtd->_read = spi_nor_read;
 
-       /* nor protection support for STmicro chips */
-       if (JEDEC_MFR(info) == CFI_MFR_ST) {
+       /* NOR protection support for STmicro/Micron chips and similar */
+       if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+           JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
                nor->flash_lock = stm_lock;
                nor->flash_unlock = stm_unlock;
+               nor->flash_is_locked = stm_is_locked;
        }
 
-       if (nor->flash_lock && nor->flash_unlock) {
+       if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
                mtd->_lock = spi_nor_lock;
                mtd->_unlock = spi_nor_unlock;
+               mtd->_is_locked = spi_nor_is_locked;
        }
 
        /* sst nor chips use AAI word program */
@@ -1163,7 +1314,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        else if (mtd->size > 0x1000000) {
                /* enable 4-byte addressing if the device exceeds 16MiB */
                nor->addr_width = 4;
-               if (JEDEC_MFR(info) == CFI_MFR_AMD) {
+               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
                        /* Dedicated 4-byte command set */
                        switch (nor->flash_read) {
                        case SPI_NOR_QUAD:
index 5a6f31af06f90c3337ae1316310e50af070d4f17..0b89418a088804e031f8e6efd137439ad02dadfe 100644 (file)
@@ -22,6 +22,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/init.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/err.h>
@@ -49,7 +50,7 @@ static int pgsize;
 static int ebcnt;
 static int pgcnt;
 static int goodebcnt;
-static struct timeval start, finish;
+static ktime_t start, finish;
 
 static int multiblock_erase(int ebnum, int blocks)
 {
@@ -168,12 +169,12 @@ static int read_eraseblock_by_2pages(int ebnum)
 
 static inline void start_timing(void)
 {
-       do_gettimeofday(&start);
+       start = ktime_get();
 }
 
 static inline void stop_timing(void)
 {
-       do_gettimeofday(&finish);
+       finish = ktime_get();
 }
 
 static long calc_speed(void)
@@ -181,8 +182,7 @@ static long calc_speed(void)
        uint64_t k;
        long ms;
 
-       ms = (finish.tv_sec - start.tv_sec) * 1000 +
-            (finish.tv_usec - start.tv_usec) / 1000;
+       ms = ktime_ms_delta(finish, start);
        if (ms == 0)
                return 0;
        k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000;
index e5d6e6d9532fa5f12961ae9aae72d0766e296370..93c2729c47b8a3e4ee1bfef76539c58a23ace8f8 100644 (file)
@@ -26,6 +26,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/init.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/err.h>
@@ -79,18 +80,18 @@ static unsigned char *check_buf;
 static unsigned int erase_cycles;
 
 static int pgsize;
-static struct timeval start, finish;
+static ktime_t start, finish;
 
 static void report_corrupt(unsigned char *read, unsigned char *written);
 
 static inline void start_timing(void)
 {
-       do_gettimeofday(&start);
+       start = ktime_get();
 }
 
 static inline void stop_timing(void)
 {
-       do_gettimeofday(&finish);
+       finish = ktime_get();
 }
 
 /*
@@ -333,8 +334,7 @@ static int __init tort_init(void)
                        long ms;
 
                        stop_timing();
-                       ms = (finish.tv_sec - start.tv_sec) * 1000 +
-                            (finish.tv_usec - start.tv_usec) / 1000;
+                       ms = ktime_ms_delta(finish, start);
                        pr_info("%08u erase cycles done, took %lu "
                               "milliseconds (%lu seconds)\n",
                               erase_cycles, ms, ms / 1000);
index b93807b4c45966f2b3cdeef1e55c4c237e1bbd3c..cb7c075f2144969d5f416d440060455ee2904933 100644 (file)
@@ -112,8 +112,8 @@ static int gluebi_get_device(struct mtd_info *mtd)
                 * The MTD device is already referenced and this is just one
                 * more reference. MTD allows many users to open the same
                 * volume simultaneously and do not distinguish between
-                * readers/writers/exclusive openers as UBI does. So we do not
-                * open the UBI volume again - just increase the reference
+                * readers/writers/exclusive/meta openers as UBI does. So we do
+                * not open the UBI volume again - just increase the reference
                 * counter and return.
                 */
                gluebi->refcnt += 1;
index 414fe7c487d598b05b574907bedd15a42b01eb3f..55a47de544ea297bb7dc8b00091ac4f15cb83954 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/etherdevice.h>
 #include <linux/net_tstamp.h>
 #include <asm/io.h>
+#include "t4_chip_type.h"
 #include "cxgb4_uld.h"
 
 #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
@@ -291,31 +292,6 @@ struct pci_params {
        unsigned char width;
 };
 
-#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
-#define CHELSIO_CHIP_FPGA          0x100
-#define CHELSIO_CHIP_VERSION(code) (((code) >> 4) & 0xf)
-#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
-
-#define CHELSIO_T4             0x4
-#define CHELSIO_T5             0x5
-#define CHELSIO_T6             0x6
-
-enum chip_type {
-       T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
-       T4_A2 = CHELSIO_CHIP_CODE(CHELSIO_T4, 2),
-       T4_FIRST_REV    = T4_A1,
-       T4_LAST_REV     = T4_A2,
-
-       T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
-       T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
-       T5_FIRST_REV    = T5_A0,
-       T5_LAST_REV     = T5_A1,
-
-       T6_A0 = CHELSIO_CHIP_CODE(CHELSIO_T6, 0),
-       T6_FIRST_REV    = T6_A0,
-       T6_LAST_REV     = T6_A0,
-};
-
 struct devlog_params {
        u32 memtype;                    /* which memory (EDC0, EDC1, MC) */
        u32 start;                      /* start of log in firmware memory */
@@ -909,21 +885,6 @@ static inline int is_offload(const struct adapter *adap)
        return adap->params.offload;
 }
 
-static inline int is_t6(enum chip_type chip)
-{
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T6;
-}
-
-static inline int is_t5(enum chip_type chip)
-{
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T5;
-}
-
-static inline int is_t4(enum chip_type chip)
-{
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4;
-}
-
 static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr)
 {
        return readl(adap->regs + reg_addr);
index 2cf81857a2971b280005715992c0842e4f21385f..0d147610a06f13819bd1425984f6ec6b3c34e81a 100644 (file)
@@ -1940,6 +1940,28 @@ unsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus,
 }
 EXPORT_SYMBOL(cxgb4_best_aligned_mtu);
 
+/**
+ *     cxgb4_tp_smt_idx - Get the Source Mac Table index for this VI
+ *     @chip: chip type
+ *     @viid: VI id of the given port
+ *
+ *     Return the SMT index for this VI.
+ */
+unsigned int cxgb4_tp_smt_idx(enum chip_type chip, unsigned int viid)
+{
+       /* In T4/T5, SMT contains 256 SMAC entries organized in
+        * 128 rows of 2 entries each.
+        * In T6, SMT contains 256 SMAC entries in 256 rows.
+        * TODO: The below code needs to be updated when we add support
+        * for 256 VFs.
+        */
+       if (CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5)
+               return ((viid & 0x7f) << 1);
+       else
+               return (viid & 0x7f);
+}
+EXPORT_SYMBOL(cxgb4_tp_smt_idx);
+
 /**
  *     cxgb4_port_chan - get the HW channel of a port
  *     @dev: the net device for the port
index c3a8be5541e7cfdbc55f41b81f12917d8561b2a4..cf711d5f15bec5498204bc97475932a72a28ea75 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/skbuff.h>
 #include <linux/inetdevice.h>
 #include <linux/atomic.h>
+#include "cxgb4.h"
 
 /* CPL message priority levels */
 enum {
@@ -290,6 +291,7 @@ int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
 unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo);
 unsigned int cxgb4_port_chan(const struct net_device *dev);
 unsigned int cxgb4_port_viid(const struct net_device *dev);
+unsigned int cxgb4_tp_smt_idx(enum chip_type chip, unsigned int viid);
 unsigned int cxgb4_port_idx(const struct net_device *dev);
 unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu,
                            unsigned int *idx);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_chip_type.h b/drivers/net/ethernet/chelsio/cxgb4/t4_chip_type.h
new file mode 100644 (file)
index 0000000..54b7181
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2015 Chelsio Communications, 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 __T4_CHIP_TYPE_H__
+#define __T4_CHIP_TYPE_H__
+
+#define CHELSIO_T4             0x4
+#define CHELSIO_T5             0x5
+#define CHELSIO_T6             0x6
+
+/* We code the Chelsio T4 Family "Chip Code" as a tuple:
+ *
+ *     (Chip Version, Chip Revision)
+ *
+ * where:
+ *
+ *     Chip Version: is T4, T5, etc.
+ *     Chip Revision: is the FAB "spin" of the Chip Version.
+ */
+#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
+#define CHELSIO_CHIP_VERSION(code) (((code) >> 4) & 0xf)
+#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
+
+enum chip_type {
+       T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
+       T4_A2 = CHELSIO_CHIP_CODE(CHELSIO_T4, 2),
+       T4_FIRST_REV    = T4_A1,
+       T4_LAST_REV     = T4_A2,
+
+       T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
+       T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
+       T5_FIRST_REV    = T5_A0,
+       T5_LAST_REV     = T5_A1,
+
+       T6_A0 = CHELSIO_CHIP_CODE(CHELSIO_T6, 0),
+       T6_FIRST_REV    = T6_A0,
+       T6_LAST_REV     = T6_A0,
+};
+
+static inline int is_t4(enum chip_type chip)
+{
+       return (CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4);
+}
+
+static inline int is_t5(enum chip_type chip)
+{
+       return (CHELSIO_CHIP_VERSION(chip) == CHELSIO_T5);
+}
+
+static inline int is_t6(enum chip_type chip)
+{
+       return (CHELSIO_CHIP_VERSION(chip) == CHELSIO_T6);
+}
+
+#endif /* __T4_CHIP_TYPE_H__ */
index b99144afd4ecc8958961acf2673c53bdcd8fa8df..a072d341e205bf272418d0104b084a0898281e7e 100644 (file)
@@ -417,6 +417,21 @@ struct cpl_t5_act_open_req {
        __be64 params;
 };
 
+struct cpl_t6_act_open_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be64 opt0;
+       __be32 rsvd;
+       __be32 opt2;
+       __be64 params;
+       __be32 rsvd2;
+       __be32 opt3;
+};
+
 struct cpl_act_open_req6 {
        WR_HDR;
        union opcode_tid ot;
@@ -446,6 +461,23 @@ struct cpl_t5_act_open_req6 {
        __be64 params;
 };
 
+struct cpl_t6_act_open_req6 {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be64 local_ip_hi;
+       __be64 local_ip_lo;
+       __be64 peer_ip_hi;
+       __be64 peer_ip_lo;
+       __be64 opt0;
+       __be32 rsvd;
+       __be32 opt2;
+       __be64 params;
+       __be32 rsvd2;
+       __be32 opt3;
+};
+
 struct cpl_act_open_rpl {
        union opcode_tid ot;
        __be32 atid_status;
@@ -504,6 +536,19 @@ struct cpl_pass_establish {
 #define TCPOPT_MSS_M   0xF
 #define TCPOPT_MSS_G(x)        (((x) >> TCPOPT_MSS_S) & TCPOPT_MSS_M)
 
+#define T6_TCP_HDR_LEN_S   8
+#define T6_TCP_HDR_LEN_V(x) ((x) << T6_TCP_HDR_LEN_S)
+#define T6_TCP_HDR_LEN_G(x) (((x) >> T6_TCP_HDR_LEN_S) & TCP_HDR_LEN_M)
+
+#define T6_IP_HDR_LEN_S    14
+#define T6_IP_HDR_LEN_V(x) ((x) << T6_IP_HDR_LEN_S)
+#define T6_IP_HDR_LEN_G(x) (((x) >> T6_IP_HDR_LEN_S) & IP_HDR_LEN_M)
+
+#define T6_ETH_HDR_LEN_S    24
+#define T6_ETH_HDR_LEN_M    0xFF
+#define T6_ETH_HDR_LEN_V(x) ((x) << T6_ETH_HDR_LEN_S)
+#define T6_ETH_HDR_LEN_G(x) (((x) >> T6_ETH_HDR_LEN_S) & T6_ETH_HDR_LEN_M)
+
 struct cpl_act_establish {
        union opcode_tid ot;
        __be32 rsvd;
@@ -833,6 +878,9 @@ struct cpl_rx_pkt {
        __be16 err_vec;
 };
 
+#define RX_T6_ETHHDR_LEN_M    0xFF
+#define RX_T6_ETHHDR_LEN_G(x) (((x) >> RX_ETHHDR_LEN_S) & RX_T6_ETHHDR_LEN_M)
+
 #define RXF_PSH_S    20
 #define RXF_PSH_V(x) ((x) << RXF_PSH_S)
 #define RXF_PSH_F    RXF_PSH_V(1U)
index ad802dd0f67a3d4fdcb6810ebdc8d66b67706d66..5b6feb7edeb167a75fc0c6c93c82e2b7e0c735d8 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/highuid.h>
 
 /* get readq/writeq support for 32 bit kernels, use the low-first version */
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 /* File to be the magic between shared code and
  * actual OS primitives
index 21a91b14bf819365bfea82276324b14da6ef403c..5e314fd3c016f314d20e487aff568069aa3b7cb6 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/pci.h>
 
 /* get readq/writeq support for 32 bit kernels, use the low-first version */
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 /* File to be the magic between shared code and
  * actual OS primitives
index a946e4bf71d2a18cce11bb497ec9b737653ae652..005f910ec955ecdaaa398c6edcc6d95c01d6c2c4 100644 (file)
@@ -123,6 +123,28 @@ void mlx4_en_update_loopback_state(struct net_device *dev,
         */
        if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
                priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
+
+       mutex_lock(&priv->mdev->state_lock);
+       if (priv->mdev->dev->caps.flags2 &
+           MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB &&
+           priv->rss_map.indir_qp.qpn) {
+               int i;
+               int err = 0;
+               int loopback = !!(features & NETIF_F_LOOPBACK);
+
+               for (i = 0; i < priv->rx_ring_num; i++) {
+                       int ret;
+
+                       ret = mlx4_en_change_mcast_lb(priv,
+                                                     &priv->rss_map.qps[i],
+                                                     loopback);
+                       if (!err)
+                               err = ret;
+               }
+               if (err)
+                       mlx4_warn(priv->mdev, "failed to change mcast loopback\n");
+       }
+       mutex_unlock(&priv->mdev->state_lock);
 }
 
 static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
index e482fa1bb7410e2eff0f2ed59948bd5fbd7decd8..12aab5a659d33e4c098a6b8bedf2d4014798e14c 100644 (file)
@@ -69,6 +69,15 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
        context->pri_path.counter_index = priv->counter_index;
        context->cqn_send = cpu_to_be32(cqn);
        context->cqn_recv = cpu_to_be32(cqn);
+       if (!rss &&
+           (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK) &&
+           context->pri_path.counter_index !=
+                           MLX4_SINK_COUNTER_INDEX(mdev->dev)) {
+               /* disable multicast loopback to qp with same counter */
+               if (!(dev->features & NETIF_F_LOOPBACK))
+                       context->pri_path.fl |= MLX4_FL_ETH_SRC_CHECK_MC_LB;
+               context->pri_path.control |= MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
+       }
        context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
        if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX))
                context->param3 |= cpu_to_be32(1 << 30);
@@ -80,6 +89,22 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
        }
 }
 
+int mlx4_en_change_mcast_lb(struct mlx4_en_priv *priv, struct mlx4_qp *qp,
+                           int loopback)
+{
+       int ret;
+       struct mlx4_update_qp_params qp_params;
+
+       memset(&qp_params, 0, sizeof(qp_params));
+       if (!loopback)
+               qp_params.flags = MLX4_UPDATE_QP_PARAMS_FLAGS_ETH_CHECK_MC_LB;
+
+       ret = mlx4_update_qp(priv->mdev->dev, qp->qpn,
+                            MLX4_UPDATE_QP_ETH_SRC_CHECK_MC_LB,
+                            &qp_params);
+
+       return ret;
+}
 
 int mlx4_en_map_buffer(struct mlx4_buf *buf)
 {
index f13a4d7bbf9597535e5f6271dea3769389bc90b6..90db94e83fdeef52023a542539a5a396c2a9a80c 100644 (file)
@@ -155,6 +155,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [27] = "Port beacon support",
                [28] = "RX-ALL support",
                [29] = "802.1ad offload support",
+               [31] = "Modifying loopback source checks using UPDATE_QP support",
+               [32] = "Loopback source checks support",
        };
        int i;
 
@@ -964,6 +966,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
        if (field32 & (1 << 16))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
+       if (field32 & (1 << 18))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB;
+       if (field32 & (1 << 19))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK;
        if (field32 & (1 << 26))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
        if (field32 & (1 << 20))
index defcf8c395bface7f024043cc51484bd7a4f3820..c41f15102ae0b7cbfd1351431ada14a223f1624e 100644 (file)
@@ -798,7 +798,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
 void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event);
 int mlx4_en_map_buffer(struct mlx4_buf *buf);
 void mlx4_en_unmap_buffer(struct mlx4_buf *buf);
-
+int mlx4_en_change_mcast_lb(struct mlx4_en_priv *priv, struct mlx4_qp *qp,
+                           int loopback);
 void mlx4_en_calc_rx_buf(struct net_device *dev);
 int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv);
 void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv);
index 3311f35d08e0719381a6e267e8cdf0acf9198b4d..168823dde79f3dd48596bdad5a4ea72a95ed0404 100644 (file)
@@ -436,6 +436,23 @@ int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
                cmd->qp_context.pri_path.grh_mylmc = params->smac_index;
        }
 
+       if (attr & MLX4_UPDATE_QP_ETH_SRC_CHECK_MC_LB) {
+               if (!(dev->caps.flags2
+                     & MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
+                       mlx4_warn(dev,
+                                 "Trying to set src check LB, but it isn't supported\n");
+                       err = -ENOTSUPP;
+                       goto out;
+               }
+               pri_addr_path_mask |=
+                       1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB;
+               if (params->flags &
+                   MLX4_UPDATE_QP_PARAMS_FLAGS_ETH_CHECK_MC_LB) {
+                       cmd->qp_context.pri_path.fl |=
+                               MLX4_FL_ETH_SRC_CHECK_MC_LB;
+               }
+       }
+
        if (attr & MLX4_UPDATE_QP_VSD) {
                qp_mask |= 1ULL << MLX4_UPD_QP_MASK_VSD;
                if (params->flags & MLX4_UPDATE_QP_PARAMS_FLAGS_VSD_ENABLE)
@@ -458,7 +475,7 @@ int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
        err = mlx4_cmd(dev, mailbox->dma, qpn & 0xffffff, 0,
                       MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A,
                       MLX4_CMD_NATIVE);
-
+out:
        mlx4_free_cmd_mailbox(dev, mailbox);
        return err;
 }
index ac4b99ab1f851c41d1fa108dcbe104f4c307cf48..9813d34f3e5b78e0b3d4a99e253b710278bc7171 100644 (file)
@@ -770,9 +770,12 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                        }
                }
 
+               /* preserve IF_COUNTER flag */
+               qpc->pri_path.vlan_control &=
+                       MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
                if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
                    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
@@ -780,12 +783,12 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
                } else if (0 != vp_oper->state.default_vlan) {
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
                } else { /* priority tagged */
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
                }
@@ -3764,9 +3767,6 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
        orig_sched_queue = qpc->pri_path.sched_queue;
-       err = update_vport_qp_param(dev, inbox, slave, qpn);
-       if (err)
-               return err;
 
        err = get_res(dev, slave, qpn, RES_QP, &qp);
        if (err)
@@ -3776,6 +3776,10 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
                goto out;
        }
 
+       err = update_vport_qp_param(dev, inbox, slave, qpn);
+       if (err)
+               goto out;
+
        err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 out:
        /* if no error, save sched queue value passed in by VF. This is
@@ -4210,7 +4214,9 @@ static int add_eth_header(struct mlx4_dev *dev, int slave,
 
 }
 
-#define MLX4_UPD_QP_PATH_MASK_SUPPORTED (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)
+#define MLX4_UPD_QP_PATH_MASK_SUPPORTED      (                                \
+       1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX                     |\
+       1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)
 int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
                           struct mlx4_vhcr *vhcr,
                           struct mlx4_cmd_mailbox *inbox,
@@ -4233,6 +4239,16 @@ int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
            (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED))
                return -EPERM;
 
+       if ((pri_addr_path_mask &
+            (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) &&
+               !(dev->caps.flags2 &
+                 MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
+                       mlx4_warn(dev,
+                                 "Src check LB for slave %d isn't supported\n",
+                                  slave);
+               return -ENOTSUPP;
+       }
+
        /* Just change the smac for the QP */
        err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
index fabfc9e0a948dfe8aa90f34f1565d76abe592f3e..037fc4cdf5af675e811f5f50950816d8dfeaff51 100644 (file)
@@ -30,7 +30,7 @@
  * SOFTWARE.
  */
 
-#include <asm-generic/kmap_types.h>
+#include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
index 2388aec208fa92fc56da476882b51fd6d0d2b6d9..4ac8d4cc49737da1d19707203aa479b832c4190a 100644 (file)
@@ -30,7 +30,7 @@
  * SOFTWARE.
  */
 
-#include <asm-generic/kmap_types.h>
+#include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
index 1cda5d268ec96e27b8121ca4b00147d576b8b48b..4d3377b126578718a0d4eca445cf37d503e86d06 100644 (file)
@@ -30,7 +30,7 @@
  * SOFTWARE.
  */
 
-#include <asm-generic/kmap_types.h>
+#include <linux/highmem.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mlx5/driver.h>
index 32a80d2df7ffc161e86feab52ee850c2660afcf9..e9f2349e98bc0f32894c4880faf98f30b7737eab 100644 (file)
@@ -36,7 +36,7 @@
 #include <net/ip_fib.h>
 #include <net/netevent.h>
 #include <net/arp.h>
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <generated/utsrelease.h>
 
 #include "rocker.h"
index 9f9832f0dea9545d619cf335cce22d412ec0d882..37b9b39192ec436c63c7eac55fdddf5060e376d9 100644 (file)
@@ -1036,7 +1036,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
        }
 
        desc = knav_pool_desc_get(netcp->tx_pool);
-       if (unlikely(IS_ERR_OR_NULL(desc))) {
+       if (IS_ERR_OR_NULL(desc)) {
                dev_err(netcp->ndev_dev, "out of TX desc\n");
                dma_unmap_single(dev, dma_addr, pkt_len, DMA_TO_DEVICE);
                return NULL;
@@ -1069,7 +1069,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
                }
 
                ndesc = knav_pool_desc_get(netcp->tx_pool);
-               if (unlikely(IS_ERR_OR_NULL(ndesc))) {
+               if (IS_ERR_OR_NULL(ndesc)) {
                        dev_err(netcp->ndev_dev, "out of TX desc for frags\n");
                        dma_unmap_page(dev, dma_addr, buf_len, DMA_TO_DEVICE);
                        goto free_descs;
index 6c195554d94ac9d690c5ffadb8fa47badc123816..97b6640a3745922fe030bbf04525a4b6de6566d6 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/types.h>
 #include <linux/pr.h>
 #include <scsi/sg.h>
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <asm/unaligned.h>
 
 #include <uapi/linux/nvme_ioctl.h>
index 59bb8556e43ac8f975485465ca8d1b0fdfeba3c5..e2a48415d9691059f1beb2afee7f134019d65ecf 100644 (file)
@@ -23,6 +23,16 @@ config OF_UNITTEST
 
          If unsure, say N here, but this option is safe to enable.
 
+config OF_ALL_DTBS
+       bool "Build all Device Tree Blobs"
+       depends on COMPILE_TEST
+       select DTC
+       help
+         This option builds all possible Device Tree Blobs (DTBs) for the
+         current architecture.
+
+         If unsure, say N here, but this option is safe to enable.
+
 config OF_FLATTREE
        bool
        select DTC
index 384574c3987c337444181d68346ce9d95963f027..cd53fe4a0c8684900a94fb4bee76f9bd668e3837 100644 (file)
@@ -330,6 +330,12 @@ int of_pci_range_to_resource(struct of_pci_range *range,
                }
                res->start = port;
        } else {
+               if ((sizeof(resource_size_t) < 8) &&
+                   upper_32_bits(range->cpu_addr)) {
+                       err = -EINVAL;
+                       goto invalid_range;
+               }
+
                res->start = range->cpu_addr;
        }
        res->end = res->start + range->size - 1;
index 8b5a187a768280c25efce25284f09875347834f1..017dd94f16ea3dd8ebbc37b81188f2d47933e878 100644 (file)
@@ -375,10 +375,7 @@ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun,
                                           cpu, thread))
                return true;
 
-       if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
-               return true;
-
-       return false;
+       return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread);
 }
 
 /**
index 6e82bc42373ba39b552adba1271c8e436fcc797c..d2430298a309a86d3f2110623d3728b9dedb228f 100644 (file)
@@ -184,7 +184,7 @@ static void * unflatten_dt_node(const void *blob,
        struct property *pp, **prev_pp = NULL;
        const char *pathp;
        unsigned int l, allocl;
-       static int depth = 0;
+       static int depth;
        int old_depth;
        int offset;
        int has_name = 0;
@@ -813,20 +813,24 @@ static int __init early_init_dt_scan_chosen_serial(void)
        if (!p || !l)
                return -ENOENT;
 
+       /* Remove console options if present */
+       l = strchrnul(p, ':') - p;
+
        /* Get the node specified by stdout-path */
-       offset = fdt_path_offset(fdt, p);
+       offset = fdt_path_offset_namelen(fdt, p, l);
        if (offset < 0)
                return -ENODEV;
 
        while (match->compatible[0]) {
-               unsigned long addr;
+               u64 addr;
+
                if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
                        match++;
                        continue;
                }
 
                addr = fdt_translate_address(fdt, offset);
-               if (!addr)
+               if (addr == OF_BAD_ADDR)
                        return -ENXIO;
 
                of_setup_earlycon(addr, match->data);
index 0baf626da56ac5b142d75367a7cfdb52747c24ce..902b89be7217137726be7eb1ab19263c0372635a 100644 (file)
@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
  * Returns a pointer to the interrupt parent node, or NULL if the interrupt
  * parent could not be determined.
  */
-struct device_node *of_irq_find_parent(struct device_node *child)
+static struct device_node *of_irq_find_parent(struct device_node *child)
 {
        struct device_node *p;
        const __be32 *parp;
@@ -501,10 +501,12 @@ void __init of_irq_init(const struct of_device_id *matches)
                 * pointer, interrupt-parent device_node etc.
                 */
                desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-               if (WARN_ON(!desc))
+               if (WARN_ON(!desc)) {
+                       of_node_put(np);
                        goto err;
+               }
 
-               desc->dev = np;
+               desc->dev = of_node_get(np);
                desc->interrupt_parent = of_irq_find_parent(np);
                if (desc->interrupt_parent == np)
                        desc->interrupt_parent = NULL;
@@ -575,6 +577,7 @@ void __init of_irq_init(const struct of_device_id *matches)
 err:
        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
                list_del(&desc->list);
+               of_node_put(desc->dev);
                kfree(desc);
        }
 }
index 5751dc5b6494d41fd0ed9fd88cc877f3d10707a0..ff27177f49edbdd3105b319c7deee29ed48da869 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/of_device.h>
 #include <linux/of_pci.h>
 #include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
 
 static inline int __of_pci_pci_compare(struct device_node *node,
                                       unsigned int data)
@@ -117,6 +118,31 @@ int of_get_pci_domain_nr(struct device_node *node)
 }
 EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
 
+/**
+ * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
+ *                           is present and valid
+ */
+void of_pci_check_probe_only(void)
+{
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(of_chosen, "linux,pci-probe-only", &val);
+       if (ret) {
+               if (ret == -ENODATA || ret == -EOVERFLOW)
+                       pr_warn("linux,pci-probe-only without valid value, ignoring\n");
+               return;
+       }
+
+       if (val)
+               pci_add_flags(PCI_PROBE_ONLY);
+       else
+               pci_clear_flags(PCI_PROBE_ONLY);
+
+       pr_info("PCI: PROBE_ONLY %sabled\n", val ? "en" : "dis");
+}
+EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
+
 /**
  * of_pci_dma_configure - Setup DMA configuration
  * @dev: ptr to pci_dev struct of the PCI device
@@ -223,8 +249,10 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
                }
 
                err = of_pci_range_to_resource(&range, dev, res);
-               if (err)
-                       goto conversion_failed;
+               if (err) {
+                       kfree(res);
+                       continue;
+               }
 
                if (resource_type(res) == IORESOURCE_IO) {
                        if (!io_base) {
index 726ebe792813011e69670a19ada489159ea6b64d..62f467b8ccae940a931a2a08ce530a9a14f46a1f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Device tree based initialization code for reserved memory.
  *
- * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013, 2015 The Linux Foundation. All Rights Reserved.
  * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  * Author: Marek Szyprowski <m.szyprowski@samsung.com>
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/sizes.h>
 #include <linux/of_reserved_mem.h>
+#include <linux/sort.h>
 
 #define MAX_RESERVED_REGIONS   16
 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
@@ -197,12 +198,52 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
        return -ENOENT;
 }
 
+static int __init __rmem_cmp(const void *a, const void *b)
+{
+       const struct reserved_mem *ra = a, *rb = b;
+
+       return ra->base - rb->base;
+}
+
+static void __init __rmem_check_for_overlap(void)
+{
+       int i;
+
+       if (reserved_mem_count < 2)
+               return;
+
+       sort(reserved_mem, reserved_mem_count, sizeof(reserved_mem[0]),
+            __rmem_cmp, NULL);
+       for (i = 0; i < reserved_mem_count - 1; i++) {
+               struct reserved_mem *this, *next;
+
+               this = &reserved_mem[i];
+               next = &reserved_mem[i + 1];
+               if (!(this->base && next->base))
+                       continue;
+               if (this->base + this->size > next->base) {
+                       phys_addr_t this_end, next_end;
+
+                       this_end = this->base + this->size;
+                       next_end = next->base + next->size;
+                       WARN(1,
+                            "Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",
+                            this->name, &this->base, &this_end,
+                            next->name, &next->base, &next_end);
+               }
+       }
+}
+
 /**
  * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
  */
 void __init fdt_init_reserved_mem(void)
 {
        int i;
+
+       /* check for overlapping reserved regions */
+       __rmem_check_for_overlap();
+
        for (i = 0; i < reserved_mem_count; i++) {
                struct reserved_mem *rmem = &reserved_mem[i];
                unsigned long node = rmem->fdt_node;
index 24e025f7929932cb1dcf8c0a834b308a30b99fe2..54e5af9d737742db1b4cb83ef3101a4ee41c7e27 100644 (file)
@@ -149,6 +149,7 @@ static int of_overlay_apply_one(struct of_overlay *ov,
                        pr_err("%s: Failed to apply single node @%s/%s\n",
                                        __func__, target->full_name,
                                        child->name);
+                       of_node_put(child);
                        return ret;
                }
        }
@@ -417,8 +418,10 @@ static int overlay_subtree_check(struct device_node *tree,
                return 1;
 
        for_each_child_of_node(tree, child) {
-               if (overlay_subtree_check(child, dn))
+               if (overlay_subtree_check(child, dn)) {
+                       of_node_put(child);
                        return 1;
+               }
        }
 
        return 0;
index 1001efaedcb8681f08f575ec80b743240dc80893..af98343614d8eeebeabc1fa0c74337029cd70335 100644 (file)
@@ -405,8 +405,10 @@ int of_platform_bus_probe(struct device_node *root,
                if (!of_match_node(matches, child))
                        continue;
                rc = of_platform_bus_create(child, matches, NULL, parent, false);
-               if (rc)
+               if (rc) {
+                       of_node_put(child);
                        break;
+               }
        }
 
        of_node_put(root);
@@ -447,8 +449,10 @@ int of_platform_populate(struct device_node *root,
 
        for_each_child_of_node(root, child) {
                rc = of_platform_bus_create(child, matches, lookup, parent, true);
-               if (rc)
+               if (rc) {
+                       of_node_put(child);
                        break;
+               }
        }
        of_node_set_flag(root, OF_POPULATED_BUS);
 
index 9f71770b6226f9ed3d4ceab7bb95ea3f4ba55b6c..e16ea5717b7f76df9c4734ee0f9373fb8e758b45 100644 (file)
@@ -205,16 +205,20 @@ static int __init of_unittest_check_node_linkage(struct device_node *np)
                if (child->parent != np) {
                        pr_err("Child node %s links to wrong parent %s\n",
                                 child->name, np->name);
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto put_child;
                }
 
                rc = of_unittest_check_node_linkage(child);
                if (rc < 0)
-                       return rc;
+                       goto put_child;
                count += rc;
        }
 
        return count + 1;
+put_child:
+       of_node_put(child);
+       return rc;
 }
 
 static void __init of_unittest_check_tree_linkage(void)
index d5e58bae95cf2dbfa74a49ddce1a51dee6e98e9d..f131ba947dc6fe47941b09b0e6d1d35f2a53c255 100644 (file)
@@ -39,7 +39,8 @@ config PCI_TEGRA
 
 config PCI_RCAR_GEN2
        bool "Renesas R-Car Gen2 Internal PCI controller"
-       depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
+       depends on ARM
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          Say Y here if you want internal PCI support on R-Car Gen2 SoC.
          There are 3 internal PCI controllers available with a single
@@ -47,7 +48,8 @@ config PCI_RCAR_GEN2
 
 config PCI_RCAR_GEN2_PCIE
        bool "Renesas R-Car PCIe controller"
-       depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
+       depends on ARM
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
 
@@ -105,7 +107,7 @@ config PCI_XGENE_MSI
 
 config PCI_LAYERSCAPE
        bool "Freescale Layerscape PCIe controller"
-       depends on OF && ARM
+       depends on OF && (ARM || ARCH_LAYERSCAPE)
        select PCIE_DW
        select MFD_SYSCON
        help
@@ -145,4 +147,29 @@ config PCIE_IPROC_BCMA
          Say Y here if you want to use the Broadcom iProc PCIe controller
          through the BCMA bus interface
 
+config PCIE_ALTERA
+       bool "Altera PCIe controller"
+       depends on ARM || NIOS2
+       depends on OF_PCI
+       select PCI_DOMAINS
+       help
+         Say Y here if you want to enable PCIe controller support on Altera
+         FPGA.
+
+config PCIE_ALTERA_MSI
+       bool "Altera PCIe MSI feature"
+       depends on PCIE_ALTERA && PCI_MSI
+       select PCI_MSI_IRQ_DOMAIN
+       help
+         Say Y here if you want PCIe MSI support for the Altera FPGA.
+         This MSI driver supports Altera MSI to GIC controller IP.
+
+config PCI_HISI
+       depends on OF && ARM64
+       bool "HiSilicon SoC HIP05 PCIe controller"
+       select PCIEPORTBUS
+       select PCIE_DW
+       help
+         Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
+
 endmenu
index 140d66f796e4b843673651bda56a00bdfb2317b1..9d4d3c6924a1da4956105c587b13e35f4ea71a43 100644 (file)
@@ -17,3 +17,6 @@ obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
 obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
 obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
 obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
+obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
+obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
+obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
index 199e29a044cdf26c8194a2475e06034640859265..8c3688046c02ff40446833f1a8f3eecebfd9713f 100644 (file)
@@ -62,6 +62,7 @@
 
 #define        PCIECTRL_DRA7XX_CONF_PHY_CS                     0x010C
 #define        LINK_UP                                         BIT(16)
+#define        DRA7XX_CPU_TO_BUS_ADDR                          0x0FFFFFFF
 
 struct dra7xx_pcie {
        void __iomem            *base;
@@ -151,6 +152,12 @@ static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
 static void dra7xx_pcie_host_init(struct pcie_port *pp)
 {
        dw_pcie_setup_rc(pp);
+
+       pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
+       pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
+       pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR;
+       pp->cfg1_base &= DRA7XX_CPU_TO_BUS_ADDR;
+
        dra7xx_pcie_establish_link(pp);
        if (IS_ENABLED(CONFIG_PCI_MSI))
                dw_pcie_msi_init(pp);
index f9f468d9a819d8402244e31805d51a034fb6392f..01095e1160a474b414112cdc1dddae1d8f3b9434 100644 (file)
@@ -454,7 +454,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        int ret;
 
        exynos_pcie_sideband_dbi_r_mode(pp, true);
-       ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+       ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
        exynos_pcie_sideband_dbi_r_mode(pp, false);
        return ret;
 }
@@ -465,8 +465,7 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
        int ret;
 
        exynos_pcie_sideband_dbi_w_mode(pp, true);
-       ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
-                       where, size, val);
+       ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
        exynos_pcie_sideband_dbi_w_mode(pp, false);
        return ret;
 }
index 265dd25169bff9d2edfe827cd9321442d7c1e47d..5434c90db24345bc73ad5e00ecc00d599c40ddaf 100644 (file)
@@ -27,7 +27,7 @@
 
 struct gen_pci_cfg_bus_ops {
        u32 bus_shift;
-       void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int);
+       struct pci_ops ops;
 };
 
 struct gen_pci_cfg_windows {
@@ -35,7 +35,7 @@ struct gen_pci_cfg_windows {
        struct resource                         *bus_range;
        void __iomem                            **win;
 
-       const struct gen_pci_cfg_bus_ops        *ops;
+       struct gen_pci_cfg_bus_ops              *ops;
 };
 
 /*
@@ -65,7 +65,11 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
 
 static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
        .bus_shift      = 16,
-       .map_bus        = gen_pci_map_cfg_bus_cam,
+       .ops            = {
+               .map_bus        = gen_pci_map_cfg_bus_cam,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
 };
 
 static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
@@ -80,12 +84,11 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
 
 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
        .bus_shift      = 20,
-       .map_bus        = gen_pci_map_cfg_bus_ecam,
-};
-
-static struct pci_ops gen_pci_ops = {
-       .read   = pci_generic_config_read,
-       .write  = pci_generic_config_write,
+       .ops            = {
+               .map_bus        = gen_pci_map_cfg_bus_ecam,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
 };
 
 static const struct of_device_id gen_pci_of_match[] = {
@@ -166,6 +169,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
        struct resource *bus_range;
        struct device *dev = pci->host.dev.parent;
        struct device_node *np = dev->of_node;
+       u32 sz = 1 << pci->cfg.ops->bus_shift;
 
        err = of_address_to_resource(np, 0, &pci->cfg.res);
        if (err) {
@@ -193,10 +197,9 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
        bus_range = pci->cfg.bus_range;
        for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
                u32 idx = busn - bus_range->start;
-               u32 sz = 1 << pci->cfg.ops->bus_shift;
 
                pci->cfg.win[idx] = devm_ioremap(dev,
-                                                pci->cfg.res.start + busn * sz,
+                                                pci->cfg.res.start + idx * sz,
                                                 sz);
                if (!pci->cfg.win[idx])
                        return -ENOMEM;
@@ -210,7 +213,6 @@ static int gen_pci_probe(struct platform_device *pdev)
        int err;
        const char *type;
        const struct of_device_id *of_id;
-       const int *prop;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
@@ -225,17 +227,10 @@ static int gen_pci_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
-       if (prop) {
-               if (*prop)
-                       pci_add_flags(PCI_PROBE_ONLY);
-               else
-                       pci_clear_flags(PCI_PROBE_ONLY);
-       }
+       of_pci_check_probe_only();
 
        of_id = of_match_node(gen_pci_of_match, np);
-       pci->cfg.ops = of_id->data;
-       gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
+       pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
        pci->host.dev.parent = dev;
        INIT_LIST_HEAD(&pci->host.windows);
        INIT_LIST_HEAD(&pci->resources);
@@ -256,7 +251,9 @@ static int gen_pci_probe(struct platform_device *pdev)
        if (!pci_has_flag(PCI_PROBE_ONLY))
                pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
 
-       bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources);
+
+       bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
+                               &pci->cfg.ops->ops, pci, &pci->resources);
        if (!bus) {
                dev_err(dev, "Scanning rootbus failed");
                return -ENODEV;
index 8f3a9813c4e55a5f16ee48e3b54ccd1ec4985702..22e8224126fd9d9885ee06f2fb81cbf1f023b06b 100644 (file)
@@ -74,6 +74,7 @@ struct imx6_pcie {
 
 /* PHY registers (not memory-mapped) */
 #define PCIE_PHY_RX_ASIC_OUT 0x100D
+#define PCIE_PHY_RX_ASIC_OUT_VALID     (1 << 0)
 
 #define PHY_RX_OVRD_IN_LO 0x1005
 #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
@@ -503,7 +504,7 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
        pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
        debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
 
-       if (rx_valid & 0x01)
+       if (rx_valid & PCIE_PHY_RX_ASIC_OUT_VALID)
                return 0;
 
        if ((debug_r0 & 0x3f) != 0x0d)
@@ -539,7 +540,7 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
                                       IRQF_SHARED, "mx6-pcie-msi", pp);
                if (ret) {
                        dev_err(&pdev->dev, "failed to request MSI irq\n");
-                       return -ENODEV;
+                       return ret;
                }
        }
 
index e71da991949b1d598444a81dd775b3117c1c4744..ed34c9520a02987503b02e2f371ea9e2a6d3a1a4 100644 (file)
@@ -70,7 +70,7 @@ static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
        *bit_pos = offset >> 3;
 }
 
-u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
+phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
 {
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
 
@@ -322,7 +322,7 @@ static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
 void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
 {
        struct pcie_port *pp = &ks_pcie->pp;
-       u32 start = pp->mem.start, end = pp->mem.end;
+       u32 start = pp->mem->start, end = pp->mem->end;
        int i, tr_size;
 
        /* Disable BARs for inbound access */
@@ -398,7 +398,7 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
        addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-       return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+       return dw_pcie_cfg_read(addr + where, size, val);
 }
 
 int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
@@ -410,7 +410,7 @@ int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 
        addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
 
-       return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+       return dw_pcie_cfg_write(addr + where, size, val);
 }
 
 /**
index 478d932b602d40cc81dd7061b103ba0973c060b3..f0944e8c4b02f4e481a9178e9dfe4107d64c83b9 100644 (file)
@@ -37,7 +37,7 @@ struct keystone_pcie {
 
 /* Keystone DW specific MSI controller APIs/definitions */
 void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
-u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
+phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
 
 /* Keystone specific PCI controller APIs */
 void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
index b2328ea13dcfe1cad3ee232c8b45f7a66cda7984..3923bed93c7e06fa8327cafef9429c34d1b063cb 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2014 Freescale Semiconductor.
  *
 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
+ * Author: Minghuan Lian <Minghuan.Lian@freescale.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
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of_pci.h>
 #define LTSSM_STATE_MASK       0x3f
 #define LTSSM_PCIE_L0          0x11 /* L0 state */
 
-/* Symbol Timer Register and Filter Mask Register 1 */
-#define PCIE_STRFMR1 0x71c
+/* PEX Internal Configuration Registers */
+#define PCIE_STRFMR1           0x71c /* Symbol Timer & Filter Mask Register1 */
+#define PCIE_DBI_RO_WR_EN      0x8bc /* DBI Read-Only Write Enable Register */
+
+/* PEX LUT registers */
+#define PCIE_LUT_DBG           0x7FC /* PEX LUT Debug Register */
+
+struct ls_pcie_drvdata {
+       u32 lut_offset;
+       u32 ltssm_shift;
+       struct pcie_host_ops *ops;
+};
 
 struct ls_pcie {
-       struct list_head node;
-       struct device *dev;
-       struct pci_bus *bus;
        void __iomem *dbi;
+       void __iomem *lut;
        struct regmap *scfg;
        struct pcie_port pp;
+       const struct ls_pcie_drvdata *drvdata;
        int index;
-       int msi_irq;
 };
 
 #define to_ls_pcie(x)  container_of(x, struct ls_pcie, pp)
 
-static int ls_pcie_link_up(struct pcie_port *pp)
+static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
+{
+       u32 header_type;
+
+       header_type = ioread8(pcie->dbi + PCI_HEADER_TYPE);
+       header_type &= 0x7f;
+
+       return header_type == PCI_HEADER_TYPE_BRIDGE;
+}
+
+/* Clear multi-function bit */
+static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
+{
+       iowrite8(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE);
+}
+
+/* Fix class value */
+static void ls_pcie_fix_class(struct ls_pcie *pcie)
+{
+       iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
+}
+
+static int ls1021_pcie_link_up(struct pcie_port *pp)
 {
        u32 state;
        struct ls_pcie *pcie = to_ls_pcie(pp);
 
+       if (!pcie->scfg)
+               return 0;
+
        regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
        state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
 
@@ -62,27 +94,27 @@ static int ls_pcie_link_up(struct pcie_port *pp)
        return 1;
 }
 
-static int ls_pcie_establish_link(struct pcie_port *pp)
+static void ls1021_pcie_host_init(struct pcie_port *pp)
 {
-       unsigned int retries;
+       struct ls_pcie *pcie = to_ls_pcie(pp);
+       u32 val, index[2];
 
-       for (retries = 0; retries < 200; retries++) {
-               if (dw_pcie_link_up(pp))
-                       return 0;
-               usleep_range(100, 1000);
+       pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node,
+                                                    "fsl,pcie-scfg");
+       if (IS_ERR(pcie->scfg)) {
+               dev_err(pp->dev, "No syscfg phandle specified\n");
+               pcie->scfg = NULL;
+               return;
        }
 
-       dev_err(pp->dev, "phy link never came up\n");
-       return -EINVAL;
-}
-
-static void ls_pcie_host_init(struct pcie_port *pp)
-{
-       struct ls_pcie *pcie = to_ls_pcie(pp);
-       u32 val;
+       if (of_property_read_u32_array(pp->dev->of_node,
+                                      "fsl,pcie-scfg", index, 2)) {
+               pcie->scfg = NULL;
+               return;
+       }
+       pcie->index = index[1];
 
        dw_pcie_setup_rc(pp);
-       ls_pcie_establish_link(pp);
 
        /*
         * LS1021A Workaround for internal TKT228622
@@ -93,21 +125,97 @@ static void ls_pcie_host_init(struct pcie_port *pp)
        iowrite32(val, pcie->dbi + PCIE_STRFMR1);
 }
 
+static int ls_pcie_link_up(struct pcie_port *pp)
+{
+       struct ls_pcie *pcie = to_ls_pcie(pp);
+       u32 state;
+
+       state = (ioread32(pcie->lut + PCIE_LUT_DBG) >>
+                pcie->drvdata->ltssm_shift) &
+                LTSSM_STATE_MASK;
+
+       if (state < LTSSM_PCIE_L0)
+               return 0;
+
+       return 1;
+}
+
+static void ls_pcie_host_init(struct pcie_port *pp)
+{
+       struct ls_pcie *pcie = to_ls_pcie(pp);
+
+       iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
+       ls_pcie_fix_class(pcie);
+       ls_pcie_clear_multifunction(pcie);
+       iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
+}
+
+static int ls_pcie_msi_host_init(struct pcie_port *pp,
+                                struct msi_controller *chip)
+{
+       struct device_node *msi_node;
+       struct device_node *np = pp->dev->of_node;
+
+       /*
+        * The MSI domain is set by the generic of_msi_configure().  This
+        * .msi_host_init() function keeps us from doing the default MSI
+        * domain setup in dw_pcie_host_init() and also enforces the
+        * requirement that "msi-parent" exists.
+        */
+       msi_node = of_parse_phandle(np, "msi-parent", 0);
+       if (!msi_node) {
+               dev_err(pp->dev, "failed to find msi-parent\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct pcie_host_ops ls1021_pcie_host_ops = {
+       .link_up = ls1021_pcie_link_up,
+       .host_init = ls1021_pcie_host_init,
+       .msi_host_init = ls_pcie_msi_host_init,
+};
+
 static struct pcie_host_ops ls_pcie_host_ops = {
        .link_up = ls_pcie_link_up,
        .host_init = ls_pcie_host_init,
+       .msi_host_init = ls_pcie_msi_host_init,
+};
+
+static struct ls_pcie_drvdata ls1021_drvdata = {
+       .ops = &ls1021_pcie_host_ops,
+};
+
+static struct ls_pcie_drvdata ls1043_drvdata = {
+       .lut_offset = 0x10000,
+       .ltssm_shift = 24,
+       .ops = &ls_pcie_host_ops,
 };
 
-static int ls_add_pcie_port(struct ls_pcie *pcie)
+static struct ls_pcie_drvdata ls2080_drvdata = {
+       .lut_offset = 0x80000,
+       .ltssm_shift = 0,
+       .ops = &ls_pcie_host_ops,
+};
+
+static const struct of_device_id ls_pcie_of_match[] = {
+       { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
+       { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
+       { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
+
+static int __init ls_add_pcie_port(struct pcie_port *pp,
+                                  struct platform_device *pdev)
 {
-       struct pcie_port *pp;
        int ret;
+       struct ls_pcie *pcie = to_ls_pcie(pp);
 
-       pp = &pcie->pp;
-       pp->dev = pcie->dev;
+       pp->dev = &pdev->dev;
        pp->dbi_base = pcie->dbi;
-       pp->root_bus_nr = -1;
-       pp->ops = &ls_pcie_host_ops;
+       pp->ops = pcie->drvdata->ops;
 
        ret = dw_pcie_host_init(pp);
        if (ret) {
@@ -120,17 +228,19 @@ static int ls_add_pcie_port(struct ls_pcie *pcie)
 
 static int __init ls_pcie_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
        struct ls_pcie *pcie;
        struct resource *dbi_base;
-       u32 index[2];
        int ret;
 
+       match = of_match_device(ls_pcie_of_match, &pdev->dev);
+       if (!match)
+               return -ENODEV;
+
        pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
        if (!pcie)
                return -ENOMEM;
 
-       pcie->dev = &pdev->dev;
-
        dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base);
        if (IS_ERR(pcie->dbi)) {
@@ -138,20 +248,13 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
                return PTR_ERR(pcie->dbi);
        }
 
-       pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-                                                    "fsl,pcie-scfg");
-       if (IS_ERR(pcie->scfg)) {
-               dev_err(&pdev->dev, "No syscfg phandle specified\n");
-               return PTR_ERR(pcie->scfg);
-       }
+       pcie->drvdata = match->data;
+       pcie->lut = pcie->dbi + pcie->drvdata->lut_offset;
 
-       ret = of_property_read_u32_array(pdev->dev.of_node,
-                                        "fsl,pcie-scfg", index, 2);
-       if (ret)
-               return ret;
-       pcie->index = index[1];
+       if (!ls_pcie_is_bridge(pcie))
+               return -ENODEV;
 
-       ret = ls_add_pcie_port(pcie);
+       ret = ls_add_pcie_port(&pcie->pp, pdev);
        if (ret < 0)
                return ret;
 
@@ -160,12 +263,6 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id ls_pcie_of_match[] = {
-       { .compatible = "fsl,ls1021a-pcie" },
-       { },
-};
-MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
-
 static struct platform_driver ls_pcie_driver = {
        .driver = {
                .name = "layerscape-pcie",
index 67ec5e1c99dbbb75a6f14943b25539ca50dc0f1e..53b79c5f055998761b837094b3ad43bd6c56de82 100644 (file)
@@ -30,6 +30,7 @@
 #define PCIE_DEV_REV_OFF       0x0008
 #define PCIE_BAR_LO_OFF(n)     (0x0010 + ((n) << 3))
 #define PCIE_BAR_HI_OFF(n)     (0x0014 + ((n) << 3))
+#define PCIE_CAP_PCIEXP                0x0060
 #define PCIE_HEADER_LOG_4_OFF  0x0128
 #define PCIE_BAR_CTRL_OFF(n)   (0x1804 + (((n) - 1) * 4))
 #define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
 #define  PCIE_STAT_BUS                  0xff00
 #define  PCIE_STAT_DEV                  0x1f0000
 #define  PCIE_STAT_LINK_DOWN           BIT(0)
+#define PCIE_RC_RTSTA          0x1a14
 #define PCIE_DEBUG_CTRL         0x1a60
 #define  PCIE_DEBUG_SOFT_RESET         BIT(20)
 
+enum {
+       PCISWCAP = PCI_BRIDGE_CONTROL + 2,
+       PCISWCAP_EXP_LIST_ID    = PCISWCAP + PCI_CAP_LIST_ID,
+       PCISWCAP_EXP_DEVCAP     = PCISWCAP + PCI_EXP_DEVCAP,
+       PCISWCAP_EXP_DEVCTL     = PCISWCAP + PCI_EXP_DEVCTL,
+       PCISWCAP_EXP_LNKCAP     = PCISWCAP + PCI_EXP_LNKCAP,
+       PCISWCAP_EXP_LNKCTL     = PCISWCAP + PCI_EXP_LNKCTL,
+       PCISWCAP_EXP_SLTCAP     = PCISWCAP + PCI_EXP_SLTCAP,
+       PCISWCAP_EXP_SLTCTL     = PCISWCAP + PCI_EXP_SLTCTL,
+       PCISWCAP_EXP_RTCTL      = PCISWCAP + PCI_EXP_RTCTL,
+       PCISWCAP_EXP_RTSTA      = PCISWCAP + PCI_EXP_RTSTA,
+       PCISWCAP_EXP_DEVCAP2    = PCISWCAP + PCI_EXP_DEVCAP2,
+       PCISWCAP_EXP_DEVCTL2    = PCISWCAP + PCI_EXP_DEVCTL2,
+       PCISWCAP_EXP_LNKCAP2    = PCISWCAP + PCI_EXP_LNKCAP2,
+       PCISWCAP_EXP_LNKCTL2    = PCISWCAP + PCI_EXP_LNKCTL2,
+       PCISWCAP_EXP_SLTCAP2    = PCISWCAP + PCI_EXP_SLTCAP2,
+       PCISWCAP_EXP_SLTCTL2    = PCISWCAP + PCI_EXP_SLTCTL2,
+};
+
 /* PCI configuration space of a PCI-to-PCI bridge */
 struct mvebu_sw_pci_bridge {
        u16 vendor;
        u16 device;
        u16 command;
+       u16 status;
        u16 class;
        u8 interface;
        u8 revision;
@@ -84,13 +106,15 @@ struct mvebu_sw_pci_bridge {
        u16 memlimit;
        u16 iobaseupper;
        u16 iolimitupper;
-       u8 cappointer;
-       u8 reserved1;
-       u16 reserved2;
        u32 romaddr;
        u8 intline;
        u8 intpin;
        u16 bridgectrl;
+
+       /* PCI express capability */
+       u32 pcie_sltcap;
+       u16 pcie_devctl;
+       u16 pcie_rtctl;
 };
 
 struct mvebu_pcie_port;
@@ -119,8 +143,7 @@ struct mvebu_pcie_port {
        unsigned int io_target;
        unsigned int io_attr;
        struct clk *clk;
-       int reset_gpio;
-       int reset_active_low;
+       struct gpio_desc *reset_gpio;
        char *reset_name;
        struct mvebu_sw_pci_bridge bridge;
        struct device_node *dn;
@@ -254,15 +277,22 @@ static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port,
                                 struct pci_bus *bus,
                                 u32 devfn, int where, int size, u32 *val)
 {
+       void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF;
+
        mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where),
                     PCIE_CONF_ADDR_OFF);
 
-       *val = mvebu_readl(port, PCIE_CONF_DATA_OFF);
-
-       if (size == 1)
-               *val = (*val >> (8 * (where & 3))) & 0xff;
-       else if (size == 2)
-               *val = (*val >> (8 * (where & 3))) & 0xffff;
+       switch (size) {
+       case 1:
+               *val = readb_relaxed(conf_data + (where & 3));
+               break;
+       case 2:
+               *val = readw_relaxed(conf_data + (where & 2));
+               break;
+       case 4:
+               *val = readl_relaxed(conf_data);
+               break;
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -271,22 +301,24 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
                                 struct pci_bus *bus,
                                 u32 devfn, int where, int size, u32 val)
 {
-       u32 _val, shift = 8 * (where & 3);
+       void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF;
 
        mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where),
                     PCIE_CONF_ADDR_OFF);
-       _val = mvebu_readl(port, PCIE_CONF_DATA_OFF);
 
-       if (size == 4)
-               _val = val;
-       else if (size == 2)
-               _val = (_val & ~(0xffff << shift)) | ((val & 0xffff) << shift);
-       else if (size == 1)
-               _val = (_val & ~(0xff << shift)) | ((val & 0xff) << shift);
-       else
+       switch (size) {
+       case 1:
+               writeb(val, conf_data + (where & 3));
+               break;
+       case 2:
+               writew(val, conf_data + (where & 2));
+               break;
+       case 4:
+               writel(val, conf_data);
+               break;
+       default:
                return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       mvebu_writel(port, _val, PCIE_CONF_DATA_OFF);
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
@@ -443,6 +475,9 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
        /* We support 32 bits I/O addressing */
        bridge->iobase = PCI_IO_RANGE_TYPE_32;
        bridge->iolimit = PCI_IO_RANGE_TYPE_32;
+
+       /* Add capabilities */
+       bridge->status = PCI_STATUS_CAP_LIST;
 }
 
 /*
@@ -460,7 +495,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                break;
 
        case PCI_COMMAND:
-               *value = bridge->command;
+               *value = bridge->command | bridge->status << 16;
                break;
 
        case PCI_CLASS_REVISION:
@@ -505,6 +540,10 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                *value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
                break;
 
+       case PCI_CAPABILITY_LIST:
+               *value = PCISWCAP;
+               break;
+
        case PCI_ROM_ADDRESS1:
                *value = 0;
                break;
@@ -514,9 +553,67 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                *value = 0;
                break;
 
+       case PCISWCAP_EXP_LIST_ID:
+               /* Set PCIe v2, root port, slot support */
+               *value = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
+                         PCI_EXP_FLAGS_SLOT) << 16 | PCI_CAP_ID_EXP;
+               break;
+
+       case PCISWCAP_EXP_DEVCAP:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCAP);
+               break;
+
+       case PCISWCAP_EXP_DEVCTL:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) &
+                                ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+                                  PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+               *value |= bridge->pcie_devctl;
+               break;
+
+       case PCISWCAP_EXP_LNKCAP:
+               /*
+                * PCIe requires the clock power management capability to be
+                * hard-wired to zero for downstream ports
+                */
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCAP) &
+                        ~PCI_EXP_LNKCAP_CLKPM;
+               break;
+
+       case PCISWCAP_EXP_LNKCTL:
+               *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
+               break;
+
+       case PCISWCAP_EXP_SLTCAP:
+               *value = bridge->pcie_sltcap;
+               break;
+
+       case PCISWCAP_EXP_SLTCTL:
+               *value = PCI_EXP_SLTSTA_PDS << 16;
+               break;
+
+       case PCISWCAP_EXP_RTCTL:
+               *value = bridge->pcie_rtctl;
+               break;
+
+       case PCISWCAP_EXP_RTSTA:
+               *value = mvebu_readl(port, PCIE_RC_RTSTA);
+               break;
+
+       /* PCIe requires the v2 fields to be hard-wired to zero */
+       case PCISWCAP_EXP_DEVCAP2:
+       case PCISWCAP_EXP_DEVCTL2:
+       case PCISWCAP_EXP_LNKCAP2:
+       case PCISWCAP_EXP_LNKCTL2:
+       case PCISWCAP_EXP_SLTCAP2:
+       case PCISWCAP_EXP_SLTCTL2:
        default:
-               *value = 0xffffffff;
-               return PCIBIOS_BAD_REGISTER_NUMBER;
+               /*
+                * PCI defines configuration read accesses to reserved or
+                * unimplemented registers to read as zero and complete
+                * normally.
+                */
+               *value = 0;
+               return PCIBIOS_SUCCESSFUL;
        }
 
        if (size == 2)
@@ -601,6 +698,51 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
                mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
                break;
 
+       case PCISWCAP_EXP_DEVCTL:
+               /*
+                * Armada370 data says these bits must always
+                * be zero when in root complex mode.
+                */
+               value &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+                          PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+
+               /*
+                * If the mask is 0xffff0000, then we only want to write
+                * the device control register, rather than clearing the
+                * RW1C bits in the device status register.  Mask out the
+                * status register bits.
+                */
+               if (mask == 0xffff0000)
+                       value &= 0xffff;
+
+               mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
+               break;
+
+       case PCISWCAP_EXP_LNKCTL:
+               /*
+                * If we don't support CLKREQ, we must ensure that the
+                * CLKREQ enable bit always reads zero.  Since we haven't
+                * had this capability, and it's dependent on board wiring,
+                * disable it for the time being.
+                */
+               value &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+
+               /*
+                * If the mask is 0xffff0000, then we only want to write
+                * the link control register, rather than clearing the
+                * RW1C bits in the link status register.  Mask out the
+                * status register bits.
+                */
+               if (mask == 0xffff0000)
+                       value &= 0xffff;
+
+               mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
+               break;
+
+       case PCISWCAP_EXP_RTSTA:
+               mvebu_writel(port, value, PCIE_RC_RTSTA);
+               break;
+
        default:
                break;
        }
@@ -652,17 +794,6 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
        if (!mvebu_pcie_link_up(port))
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       /*
-        * On the secondary bus, we don't want to expose any other
-        * device than the device physically connected in the PCIe
-        * slot, visible in slot 0. In slot 1, there's a special
-        * Marvell device that only makes sense when the Armada is
-        * used as a PCIe endpoint.
-        */
-       if (bus->number == port->bridge.secondary_bus &&
-           PCI_SLOT(devfn) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
        /* Access the real PCIe interface */
        ret = mvebu_pcie_hw_wr_conf(port, bus, devfn,
                                    where, size, val);
@@ -693,19 +824,6 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
 
-       /*
-        * On the secondary bus, we don't want to expose any other
-        * device than the device physically connected in the PCIe
-        * slot, visible in slot 0. In slot 1, there's a special
-        * Marvell device that only makes sense when the Armada is
-        * used as a PCIe endpoint.
-        */
-       if (bus->number == port->bridge.secondary_bus &&
-           PCI_SLOT(devfn) != 0) {
-               *val = 0xffffffff;
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       }
-
        /* Access the real PCIe interface */
        ret = mvebu_pcie_hw_rd_conf(port, bus, devfn,
                                    where, size, val);
@@ -914,12 +1032,167 @@ static int mvebu_pcie_resume(struct device *dev)
        return 0;
 }
 
+static void mvebu_pcie_port_clk_put(void *data)
+{
+       struct mvebu_pcie_port *port = data;
+
+       clk_put(port->clk);
+}
+
+static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
+       struct mvebu_pcie_port *port, struct device_node *child)
+{
+       struct device *dev = &pcie->pdev->dev;
+       enum of_gpio_flags flags;
+       int reset_gpio, ret;
+
+       port->pcie = pcie;
+
+       if (of_property_read_u32(child, "marvell,pcie-port", &port->port)) {
+               dev_warn(dev, "ignoring %s, missing pcie-port property\n",
+                        of_node_full_name(child));
+               goto skip;
+       }
+
+       if (of_property_read_u32(child, "marvell,pcie-lane", &port->lane))
+               port->lane = 0;
+
+       port->name = devm_kasprintf(dev, GFP_KERNEL, "pcie%d.%d", port->port,
+                                   port->lane);
+       if (!port->name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       port->devfn = of_pci_get_devfn(child);
+       if (port->devfn < 0)
+               goto skip;
+
+       ret = mvebu_get_tgt_attr(dev->of_node, port->devfn, IORESOURCE_MEM,
+                                &port->mem_target, &port->mem_attr);
+       if (ret < 0) {
+               dev_err(dev, "%s: cannot get tgt/attr for mem window\n",
+                       port->name);
+               goto skip;
+       }
+
+       if (resource_size(&pcie->io) != 0) {
+               mvebu_get_tgt_attr(dev->of_node, port->devfn, IORESOURCE_IO,
+                                  &port->io_target, &port->io_attr);
+       } else {
+               port->io_target = -1;
+               port->io_attr = -1;
+       }
+
+       reset_gpio = of_get_named_gpio_flags(child, "reset-gpios", 0, &flags);
+       if (reset_gpio == -EPROBE_DEFER) {
+               ret = reset_gpio;
+               goto err;
+       }
+
+       if (gpio_is_valid(reset_gpio)) {
+               unsigned long gpio_flags;
+
+               port->reset_name = devm_kasprintf(dev, GFP_KERNEL, "%s-reset",
+                                                 port->name);
+               if (!port->reset_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               if (flags & OF_GPIO_ACTIVE_LOW) {
+                       dev_info(dev, "%s: reset gpio is active low\n",
+                                of_node_full_name(child));
+                       gpio_flags = GPIOF_ACTIVE_LOW |
+                                    GPIOF_OUT_INIT_LOW;
+               } else {
+                       gpio_flags = GPIOF_OUT_INIT_HIGH;
+               }
+
+               ret = devm_gpio_request_one(dev, reset_gpio, gpio_flags,
+                                           port->reset_name);
+               if (ret) {
+                       if (ret == -EPROBE_DEFER)
+                               goto err;
+                       goto skip;
+               }
+
+               port->reset_gpio = gpio_to_desc(reset_gpio);
+       }
+
+       port->clk = of_clk_get_by_name(child, NULL);
+       if (IS_ERR(port->clk)) {
+               dev_err(dev, "%s: cannot get clock\n", port->name);
+               goto skip;
+       }
+
+       ret = devm_add_action(dev, mvebu_pcie_port_clk_put, port);
+       if (ret < 0) {
+               clk_put(port->clk);
+               goto err;
+       }
+
+       return 1;
+
+skip:
+       ret = 0;
+
+       /* In the case of skipping, we need to free these */
+       devm_kfree(dev, port->reset_name);
+       port->reset_name = NULL;
+       devm_kfree(dev, port->name);
+       port->name = NULL;
+
+err:
+       return ret;
+}
+
+/*
+ * Power up a PCIe port.  PCIe requires the refclk to be stable for 100µs
+ * prior to releasing PERST.  See table 2-4 in section 2.6.2 AC Specifications
+ * of the PCI Express Card Electromechanical Specification, 1.1.
+ */
+static int mvebu_pcie_powerup(struct mvebu_pcie_port *port)
+{
+       int ret;
+
+       ret = clk_prepare_enable(port->clk);
+       if (ret < 0)
+               return ret;
+
+       if (port->reset_gpio) {
+               u32 reset_udelay = 20000;
+
+               of_property_read_u32(port->dn, "reset-delay-us",
+                                    &reset_udelay);
+
+               udelay(100);
+
+               gpiod_set_value_cansleep(port->reset_gpio, 0);
+               msleep(reset_udelay / 1000);
+       }
+
+       return 0;
+}
+
+/*
+ * Power down a PCIe port.  Strictly, PCIe requires us to place the card
+ * in D3hot state before asserting PERST#.
+ */
+static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port)
+{
+       if (port->reset_gpio)
+               gpiod_set_value_cansleep(port->reset_gpio, 1);
+
+       clk_disable_unprepare(port->clk);
+}
+
 static int mvebu_pcie_probe(struct platform_device *pdev)
 {
        struct mvebu_pcie *pcie;
        struct device_node *np = pdev->dev.of_node;
        struct device_node *child;
-       int i, ret;
+       int num, i, ret;
 
        pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
                            GFP_KERNEL);
@@ -955,112 +1228,52 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
                return ret;
        }
 
-       i = 0;
-       for_each_child_of_node(pdev->dev.of_node, child) {
-               if (!of_device_is_available(child))
-                       continue;
-               i++;
-       }
+       num = of_get_available_child_count(pdev->dev.of_node);
 
-       pcie->ports = devm_kzalloc(&pdev->dev, i *
-                                  sizeof(struct mvebu_pcie_port),
+       pcie->ports = devm_kcalloc(&pdev->dev, num, sizeof(*pcie->ports),
                                   GFP_KERNEL);
        if (!pcie->ports)
                return -ENOMEM;
 
        i = 0;
-       for_each_child_of_node(pdev->dev.of_node, child) {
+       for_each_available_child_of_node(pdev->dev.of_node, child) {
                struct mvebu_pcie_port *port = &pcie->ports[i];
-               enum of_gpio_flags flags;
-
-               if (!of_device_is_available(child))
-                       continue;
 
-               port->pcie = pcie;
-
-               if (of_property_read_u32(child, "marvell,pcie-port",
-                                        &port->port)) {
-                       dev_warn(&pdev->dev,
-                                "ignoring PCIe DT node, missing pcie-port property\n");
-                       continue;
-               }
-
-               if (of_property_read_u32(child, "marvell,pcie-lane",
-                                        &port->lane))
-                       port->lane = 0;
-
-               port->name = kasprintf(GFP_KERNEL, "pcie%d.%d",
-                                      port->port, port->lane);
-
-               port->devfn = of_pci_get_devfn(child);
-               if (port->devfn < 0)
-                       continue;
-
-               ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_MEM,
-                                        &port->mem_target, &port->mem_attr);
+               ret = mvebu_pcie_parse_port(pcie, port, child);
                if (ret < 0) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for mem window\n",
-                               port->port, port->lane);
+                       of_node_put(child);
+                       return ret;
+               } else if (ret == 0) {
                        continue;
                }
 
-               if (resource_size(&pcie->io) != 0)
-                       mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
-                                          &port->io_target, &port->io_attr);
-               else {
-                       port->io_target = -1;
-                       port->io_attr = -1;
-               }
+               port->dn = child;
+               i++;
+       }
+       pcie->nports = i;
 
-               port->reset_gpio = of_get_named_gpio_flags(child,
-                                                  "reset-gpios", 0, &flags);
-               if (gpio_is_valid(port->reset_gpio)) {
-                       u32 reset_udelay = 20000;
-
-                       port->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
-                       port->reset_name = kasprintf(GFP_KERNEL,
-                                    "pcie%d.%d-reset", port->port, port->lane);
-                       of_property_read_u32(child, "reset-delay-us",
-                                            &reset_udelay);
-
-                       ret = devm_gpio_request_one(&pdev->dev,
-                           port->reset_gpio, GPIOF_DIR_OUT, port->reset_name);
-                       if (ret) {
-                               if (ret == -EPROBE_DEFER)
-                                       return ret;
-                               continue;
-                       }
-
-                       gpio_set_value(port->reset_gpio,
-                                      (port->reset_active_low) ? 1 : 0);
-                       msleep(reset_udelay/1000);
-               }
+       for (i = 0; i < pcie->nports; i++) {
+               struct mvebu_pcie_port *port = &pcie->ports[i];
 
-               port->clk = of_clk_get_by_name(child, NULL);
-               if (IS_ERR(port->clk)) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
-                              port->port, port->lane);
+               child = port->dn;
+               if (!child)
                        continue;
-               }
 
-               ret = clk_prepare_enable(port->clk);
-               if (ret)
+               ret = mvebu_pcie_powerup(port);
+               if (ret < 0)
                        continue;
 
                port->base = mvebu_pcie_map_registers(pdev, child, port);
                if (IS_ERR(port->base)) {
-                       dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
-                               port->port, port->lane);
+                       dev_err(&pdev->dev, "%s: cannot map registers\n",
+                               port->name);
                        port->base = NULL;
-                       clk_disable_unprepare(port->clk);
+                       mvebu_pcie_powerdown(port);
                        continue;
                }
 
                mvebu_pcie_set_local_dev_nr(port, 1);
-
-               port->dn = child;
                mvebu_sw_pci_bridge_init(port);
-               i++;
        }
 
        pcie->nports = i;
index 81df0c1fe063ff164aef16eb2cfc449539a8a107..3018ae52e0923d4e2e8c8c2dc75f07d5528598bc 100644 (file)
@@ -382,8 +382,8 @@ static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where)
 static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
                                                   unsigned int busnr)
 {
-       pgprot_t prot = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN |
-                       L_PTE_MT_DEV_SHARED | L_PTE_SHARED;
+       pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                                L_PTE_XN | L_PTE_MT_DEV_SHARED | L_PTE_SHARED);
        phys_addr_t cs = pcie->cs->start;
        struct tegra_pcie_bus *bus;
        unsigned int i;
index 0236ab9d5720133b57536c916591aab580157b28..ae00ce22d5a6eb2c7c2263f13a3fe0113c45da27 100644 (file)
@@ -509,24 +509,6 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
        return 0;
 }
 
-static int xgene_pcie_msi_enable(struct pci_bus *bus)
-{
-       struct device_node *msi_node;
-
-       msi_node = of_parse_phandle(bus->dev.of_node,
-                                       "msi-parent", 0);
-       if (!msi_node)
-               return -ENODEV;
-
-       bus->msi = of_pci_find_msi_chip_by_node(msi_node);
-       if (!bus->msi)
-               return -ENODEV;
-
-       of_node_put(msi_node);
-       bus->msi->dev = &bus->dev;
-       return 0;
-}
-
 static int xgene_pcie_probe_bridge(struct platform_device *pdev)
 {
        struct device_node *dn = pdev->dev.of_node;
@@ -567,10 +549,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        if (!bus)
                return -ENOMEM;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               if (xgene_pcie_msi_enable(bus))
-                       dev_info(port->dev, "failed to enable MSI\n");
-
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
        pci_bus_add_devices(bus);
diff --git a/drivers/pci/host/pcie-altera-msi.c b/drivers/pci/host/pcie-altera-msi.c
new file mode 100644 (file)
index 0000000..99177f4
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright Altera Corporation (C) 2013-2015. All rights reserved
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define MSI_STATUS             0x0
+#define MSI_ERROR              0x4
+#define MSI_INTMASK            0x8
+
+#define MAX_MSI_VECTORS                32
+
+struct altera_msi {
+       DECLARE_BITMAP(used, MAX_MSI_VECTORS);
+       struct mutex            lock;   /* protect "used" bitmap */
+       struct platform_device  *pdev;
+       struct irq_domain       *msi_domain;
+       struct irq_domain       *inner_domain;
+       void __iomem            *csr_base;
+       void __iomem            *vector_base;
+       phys_addr_t             vector_phy;
+       u32                     num_of_vectors;
+       int                     irq;
+};
+
+static inline void msi_writel(struct altera_msi *msi, const u32 value,
+                             const u32 reg)
+{
+       writel_relaxed(value, msi->csr_base + reg);
+}
+
+static inline u32 msi_readl(struct altera_msi *msi, const u32 reg)
+{
+       return readl_relaxed(msi->csr_base + reg);
+}
+
+static void altera_msi_isr(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct altera_msi *msi;
+       unsigned long status;
+       u32 num_of_vectors;
+       u32 bit;
+       u32 virq;
+
+       chained_irq_enter(chip, desc);
+       msi = irq_desc_get_handler_data(desc);
+       num_of_vectors = msi->num_of_vectors;
+
+       while ((status = msi_readl(msi, MSI_STATUS)) != 0) {
+               for_each_set_bit(bit, &status, msi->num_of_vectors) {
+                       /* Dummy read from vector to clear the interrupt */
+                       readl_relaxed(msi->vector_base + (bit * sizeof(u32)));
+
+                       virq = irq_find_mapping(msi->inner_domain, bit);
+                       if (virq)
+                               generic_handle_irq(virq);
+                       else
+                               dev_err(&msi->pdev->dev, "unexpected MSI\n");
+               }
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip altera_msi_irq_chip = {
+       .name = "Altera PCIe MSI",
+       .irq_mask = pci_msi_mask_irq,
+       .irq_unmask = pci_msi_unmask_irq,
+};
+
+static struct msi_domain_info altera_msi_domain_info = {
+       .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+                    MSI_FLAG_PCI_MSIX),
+       .chip   = &altera_msi_irq_chip,
+};
+
+static void altera_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+       struct altera_msi *msi = irq_data_get_irq_chip_data(data);
+       phys_addr_t addr = msi->vector_phy + (data->hwirq * sizeof(u32));
+
+       msg->address_lo = lower_32_bits(addr);
+       msg->address_hi = upper_32_bits(addr);
+       msg->data = data->hwirq;
+
+       dev_dbg(&msi->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n",
+               (int)data->hwirq, msg->address_hi, msg->address_lo);
+}
+
+static int altera_msi_set_affinity(struct irq_data *irq_data,
+                                  const struct cpumask *mask, bool force)
+{
+        return -EINVAL;
+}
+
+static struct irq_chip altera_msi_bottom_irq_chip = {
+       .name                   = "Altera MSI",
+       .irq_compose_msi_msg    = altera_compose_msi_msg,
+       .irq_set_affinity       = altera_msi_set_affinity,
+};
+
+static int altera_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                                  unsigned int nr_irqs, void *args)
+{
+       struct altera_msi *msi = domain->host_data;
+       unsigned long bit;
+       u32 mask;
+
+       WARN_ON(nr_irqs != 1);
+       mutex_lock(&msi->lock);
+
+       bit = find_first_zero_bit(msi->used, msi->num_of_vectors);
+       if (bit >= msi->num_of_vectors) {
+               mutex_unlock(&msi->lock);
+               return -ENOSPC;
+       }
+
+       set_bit(bit, msi->used);
+
+       mutex_unlock(&msi->lock);
+
+       irq_domain_set_info(domain, virq, bit, &altera_msi_bottom_irq_chip,
+                           domain->host_data, handle_simple_irq,
+                           NULL, NULL);
+
+       mask = msi_readl(msi, MSI_INTMASK);
+       mask |= 1 << bit;
+       msi_writel(msi, mask, MSI_INTMASK);
+
+       return 0;
+}
+
+static void altera_irq_domain_free(struct irq_domain *domain,
+                                  unsigned int virq, unsigned int nr_irqs)
+{
+       struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+       struct altera_msi *msi = irq_data_get_irq_chip_data(d);
+       u32 mask;
+
+       mutex_lock(&msi->lock);
+
+       if (!test_bit(d->hwirq, msi->used)) {
+               dev_err(&msi->pdev->dev, "trying to free unused MSI#%lu\n",
+                       d->hwirq);
+       } else {
+               __clear_bit(d->hwirq, msi->used);
+               mask = msi_readl(msi, MSI_INTMASK);
+               mask &= ~(1 << d->hwirq);
+               msi_writel(msi, mask, MSI_INTMASK);
+       }
+
+       mutex_unlock(&msi->lock);
+}
+
+static const struct irq_domain_ops msi_domain_ops = {
+       .alloc  = altera_irq_domain_alloc,
+       .free   = altera_irq_domain_free,
+};
+
+static int altera_allocate_domains(struct altera_msi *msi)
+{
+       struct fwnode_handle *fwnode = of_node_to_fwnode(msi->pdev->dev.of_node);
+
+       msi->inner_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
+                                            &msi_domain_ops, msi);
+       if (!msi->inner_domain) {
+               dev_err(&msi->pdev->dev, "failed to create IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       msi->msi_domain = pci_msi_create_irq_domain(fwnode,
+                               &altera_msi_domain_info, msi->inner_domain);
+       if (!msi->msi_domain) {
+               dev_err(&msi->pdev->dev, "failed to create MSI domain\n");
+               irq_domain_remove(msi->inner_domain);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void altera_free_domains(struct altera_msi *msi)
+{
+       irq_domain_remove(msi->msi_domain);
+       irq_domain_remove(msi->inner_domain);
+}
+
+static int altera_msi_remove(struct platform_device *pdev)
+{
+       struct altera_msi *msi = platform_get_drvdata(pdev);
+
+       msi_writel(msi, 0, MSI_INTMASK);
+       irq_set_chained_handler(msi->irq, NULL);
+       irq_set_handler_data(msi->irq, NULL);
+
+       altera_free_domains(msi);
+
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static int altera_msi_probe(struct platform_device *pdev)
+{
+       struct altera_msi *msi;
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+       int ret;
+
+       msi = devm_kzalloc(&pdev->dev, sizeof(struct altera_msi),
+                          GFP_KERNEL);
+       if (!msi)
+               return -ENOMEM;
+
+       mutex_init(&msi->lock);
+       msi->pdev = pdev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
+       if (!res) {
+               dev_err(&pdev->dev, "no csr memory resource defined\n");
+               return -ENODEV;
+       }
+
+       msi->csr_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(msi->csr_base)) {
+               dev_err(&pdev->dev, "failed to map csr memory\n");
+               return PTR_ERR(msi->csr_base);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "vector_slave");
+       if (!res) {
+               dev_err(&pdev->dev, "no vector_slave memory resource defined\n");
+               return -ENODEV;
+       }
+
+       msi->vector_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(msi->vector_base)) {
+               dev_err(&pdev->dev, "failed to map vector_slave memory\n");
+               return PTR_ERR(msi->vector_base);
+       }
+
+       msi->vector_phy = res->start;
+
+       if (of_property_read_u32(np, "num-vectors", &msi->num_of_vectors)) {
+               dev_err(&pdev->dev, "failed to parse the number of vectors\n");
+               return -EINVAL;
+       }
+
+       ret = altera_allocate_domains(msi);
+       if (ret)
+               return ret;
+
+       msi->irq = platform_get_irq(pdev, 0);
+       if (msi->irq <= 0) {
+               dev_err(&pdev->dev, "failed to map IRQ: %d\n", msi->irq);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       irq_set_chained_handler_and_data(msi->irq, altera_msi_isr, msi);
+       platform_set_drvdata(pdev, msi);
+
+       return 0;
+
+err:
+       altera_msi_remove(pdev);
+       return ret;
+}
+
+static const struct of_device_id altera_msi_of_match[] = {
+       { .compatible = "altr,msi-1.0", NULL },
+       { },
+};
+
+static struct platform_driver altera_msi_driver = {
+       .driver = {
+               .name = "altera-msi",
+               .of_match_table = altera_msi_of_match,
+       },
+       .probe = altera_msi_probe,
+       .remove = altera_msi_remove,
+};
+
+static int __init altera_msi_init(void)
+{
+       return platform_driver_register(&altera_msi_driver);
+}
+subsys_initcall(altera_msi_init);
+
+MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
+MODULE_DESCRIPTION("Altera PCIe MSI support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
new file mode 100644 (file)
index 0000000..e5dda38
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright Altera Corporation (C) 2013-2015. All rights reserved
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define RP_TX_REG0                     0x2000
+#define RP_TX_REG1                     0x2004
+#define RP_TX_CNTRL                    0x2008
+#define RP_TX_EOP                      0x2
+#define RP_TX_SOP                      0x1
+#define RP_RXCPL_STATUS                        0x2010
+#define RP_RXCPL_EOP                   0x2
+#define RP_RXCPL_SOP                   0x1
+#define RP_RXCPL_REG0                  0x2014
+#define RP_RXCPL_REG1                  0x2018
+#define P2A_INT_STATUS                 0x3060
+#define P2A_INT_STS_ALL                        0xf
+#define P2A_INT_ENABLE                 0x3070
+#define P2A_INT_ENA_ALL                        0xf
+#define RP_LTSSM                       0x3c64
+#define LTSSM_L0                       0xf
+
+/* TLP configuration type 0 and 1 */
+#define TLP_FMTTYPE_CFGRD0             0x04    /* Configuration Read Type 0 */
+#define TLP_FMTTYPE_CFGWR0             0x44    /* Configuration Write Type 0 */
+#define TLP_FMTTYPE_CFGRD1             0x05    /* Configuration Read Type 1 */
+#define TLP_FMTTYPE_CFGWR1             0x45    /* Configuration Write Type 1 */
+#define TLP_PAYLOAD_SIZE               0x01
+#define TLP_READ_TAG                   0x1d
+#define TLP_WRITE_TAG                  0x10
+#define TLP_CFG_DW0(fmttype)           (((fmttype) << 24) | TLP_PAYLOAD_SIZE)
+#define TLP_CFG_DW1(reqid, tag, be)    (((reqid) << 16) | (tag << 8) | (be))
+#define TLP_CFG_DW2(bus, devfn, offset)        \
+                               (((bus) << 24) | ((devfn) << 16) | (offset))
+#define TLP_REQ_ID(bus, devfn)         (((bus) << 8) | (devfn))
+#define TLP_HDR_SIZE                   3
+#define TLP_LOOP                       500
+
+#define INTX_NUM                       4
+
+#define DWORD_MASK                     3
+
+struct altera_pcie {
+       struct platform_device  *pdev;
+       void __iomem            *cra_base;
+       int                     irq;
+       u8                      root_bus_nr;
+       struct irq_domain       *irq_domain;
+       struct resource         bus_range;
+       struct list_head        resources;
+};
+
+struct tlp_rp_regpair_t {
+       u32 ctrl;
+       u32 reg0;
+       u32 reg1;
+};
+
+static void altera_pcie_retrain(struct pci_dev *dev)
+{
+       u16 linkcap, linkstat;
+
+       /*
+        * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
+        * current speed is 2.5 GB/s.
+        */
+       pcie_capability_read_word(dev, PCI_EXP_LNKCAP, &linkcap);
+
+       if ((linkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+               return;
+
+       pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &linkstat);
+       if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB)
+               pcie_capability_set_word(dev, PCI_EXP_LNKCTL,
+                                        PCI_EXP_LNKCTL_RL);
+}
+DECLARE_PCI_FIXUP_EARLY(0x1172, PCI_ANY_ID, altera_pcie_retrain);
+
+/*
+ * Altera PCIe port uses BAR0 of RC's configuration space as the translation
+ * from PCI bus to native BUS.  Entire DDR region is mapped into PCIe space
+ * using these registers, so it can be reached by DMA from EP devices.
+ * This BAR0 will also access to MSI vector when receiving MSI/MSIX interrupt
+ * from EP devices, eventually trigger interrupt to GIC.  The BAR0 of bridge
+ * should be hidden during enumeration to avoid the sizing and resource
+ * allocation by PCIe core.
+ */
+static bool altera_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int  devfn,
+                                   int offset)
+{
+       if (pci_is_root_bus(bus) && (devfn == 0) &&
+           (offset == PCI_BASE_ADDRESS_0))
+               return true;
+
+       return false;
+}
+
+static inline void cra_writel(struct altera_pcie *pcie, const u32 value,
+                             const u32 reg)
+{
+       writel_relaxed(value, pcie->cra_base + reg);
+}
+
+static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
+{
+       return readl_relaxed(pcie->cra_base + reg);
+}
+
+static void tlp_write_tx(struct altera_pcie *pcie,
+                        struct tlp_rp_regpair_t *tlp_rp_regdata)
+{
+       cra_writel(pcie, tlp_rp_regdata->reg0, RP_TX_REG0);
+       cra_writel(pcie, tlp_rp_regdata->reg1, RP_TX_REG1);
+       cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL);
+}
+
+static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
+{
+       return !!(cra_readl(pcie, RP_LTSSM) & LTSSM_L0);
+}
+
+static bool altera_pcie_valid_config(struct altera_pcie *pcie,
+                                    struct pci_bus *bus, int dev)
+{
+       /* If there is no link, then there is no device */
+       if (bus->number != pcie->root_bus_nr) {
+               if (!altera_pcie_link_is_up(pcie))
+                       return false;
+       }
+
+       /* access only one slot on each root port */
+       if (bus->number == pcie->root_bus_nr && dev > 0)
+               return false;
+
+       /*
+        * Do not read more than one device on the bus directly attached
+        * to root port, root port can only attach to one downstream port.
+        */
+       if (bus->primary == pcie->root_bus_nr && dev > 0)
+               return false;
+
+        return true;
+}
+
+static int tlp_read_packet(struct altera_pcie *pcie, u32 *value)
+{
+       u8 loop;
+       bool sop = 0;
+       u32 ctrl;
+       u32 reg0, reg1;
+
+       /*
+        * Minimum 2 loops to read TLP headers and 1 loop to read data
+        * payload.
+        */
+       for (loop = 0; loop < TLP_LOOP; loop++) {
+               ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
+               if ((ctrl & RP_RXCPL_SOP) || (ctrl & RP_RXCPL_EOP) || sop) {
+                       reg0 = cra_readl(pcie, RP_RXCPL_REG0);
+                       reg1 = cra_readl(pcie, RP_RXCPL_REG1);
+
+                       if (ctrl & RP_RXCPL_SOP)
+                               sop = true;
+
+                       if (ctrl & RP_RXCPL_EOP) {
+                               if (value)
+                                       *value = reg0;
+                               return PCIBIOS_SUCCESSFUL;
+                       }
+               }
+               udelay(5);
+       }
+
+       return -ENOENT;
+}
+
+static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers,
+                            u32 data, bool align)
+{
+       struct tlp_rp_regpair_t tlp_rp_regdata;
+
+       tlp_rp_regdata.reg0 = headers[0];
+       tlp_rp_regdata.reg1 = headers[1];
+       tlp_rp_regdata.ctrl = RP_TX_SOP;
+       tlp_write_tx(pcie, &tlp_rp_regdata);
+
+       if (align) {
+               tlp_rp_regdata.reg0 = headers[2];
+               tlp_rp_regdata.reg1 = 0;
+               tlp_rp_regdata.ctrl = 0;
+               tlp_write_tx(pcie, &tlp_rp_regdata);
+
+               tlp_rp_regdata.reg0 = data;
+               tlp_rp_regdata.reg1 = 0;
+       } else {
+               tlp_rp_regdata.reg0 = headers[2];
+               tlp_rp_regdata.reg1 = data;
+       }
+
+       tlp_rp_regdata.ctrl = RP_TX_EOP;
+       tlp_write_tx(pcie, &tlp_rp_regdata);
+}
+
+static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn,
+                             int where, u8 byte_en, u32 *value)
+{
+       u32 headers[TLP_HDR_SIZE];
+
+       if (bus == pcie->root_bus_nr)
+               headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD0);
+       else
+               headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1);
+
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+                                       TLP_READ_TAG, byte_en);
+       headers[2] = TLP_CFG_DW2(bus, devfn, where);
+
+       tlp_write_packet(pcie, headers, 0, false);
+
+       return tlp_read_packet(pcie, value);
+}
+
+static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
+                              int where, u8 byte_en, u32 value)
+{
+       u32 headers[TLP_HDR_SIZE];
+       int ret;
+
+       if (bus == pcie->root_bus_nr)
+               headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR0);
+       else
+               headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1);
+
+       headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+                                       TLP_WRITE_TAG, byte_en);
+       headers[2] = TLP_CFG_DW2(bus, devfn, where);
+
+       /* check alignment to Qword */
+       if ((where & 0x7) == 0)
+               tlp_write_packet(pcie, headers, value, true);
+       else
+               tlp_write_packet(pcie, headers, value, false);
+
+       ret = tlp_read_packet(pcie, NULL);
+       if (ret != PCIBIOS_SUCCESSFUL)
+               return ret;
+
+       /*
+        * Monitor changes to PCI_PRIMARY_BUS register on root port
+        * and update local copy of root bus number accordingly.
+        */
+       if ((bus == pcie->root_bus_nr) && (where == PCI_PRIMARY_BUS))
+               pcie->root_bus_nr = (u8)(value);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
+                               int where, int size, u32 *value)
+{
+       struct altera_pcie *pcie = bus->sysdata;
+       int ret;
+       u32 data;
+       u8 byte_en;
+
+       if (altera_pcie_hide_rc_bar(bus, devfn, where))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) {
+               *value = 0xffffffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       switch (size) {
+       case 1:
+               byte_en = 1 << (where & 3);
+               break;
+       case 2:
+               byte_en = 3 << (where & 3);
+               break;
+       default:
+               byte_en = 0xf;
+               break;
+       }
+
+       ret = tlp_cfg_dword_read(pcie, bus->number, devfn,
+                                (where & ~DWORD_MASK), byte_en, &data);
+       if (ret != PCIBIOS_SUCCESSFUL)
+               return ret;
+
+       switch (size) {
+       case 1:
+               *value = (data >> (8 * (where & 0x3))) & 0xff;
+               break;
+       case 2:
+               *value = (data >> (8 * (where & 0x2))) & 0xffff;
+               break;
+       default:
+               *value = data;
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 value)
+{
+       struct altera_pcie *pcie = bus->sysdata;
+       u32 data32;
+       u32 shift = 8 * (where & 3);
+       u8 byte_en;
+
+       if (altera_pcie_hide_rc_bar(bus, devfn, where))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn)))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       switch (size) {
+       case 1:
+               data32 = (value & 0xff) << shift;
+               byte_en = 1 << (where & 3);
+               break;
+       case 2:
+               data32 = (value & 0xffff) << shift;
+               byte_en = 3 << (where & 3);
+               break;
+       default:
+               data32 = value;
+               byte_en = 0xf;
+               break;
+       }
+
+       return tlp_cfg_dword_write(pcie, bus->number, devfn,
+               (where & ~DWORD_MASK), byte_en, data32);
+}
+
+static struct pci_ops altera_pcie_ops = {
+       .read = altera_pcie_cfg_read,
+       .write = altera_pcie_cfg_write,
+};
+
+static int altera_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+       irq_set_chip_data(irq, domain->host_data);
+
+       return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+       .map = altera_pcie_intx_map,
+};
+
+static void altera_pcie_isr(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct altera_pcie *pcie;
+       unsigned long status;
+       u32 bit;
+       u32 virq;
+
+       chained_irq_enter(chip, desc);
+       pcie = irq_desc_get_handler_data(desc);
+
+       while ((status = cra_readl(pcie, P2A_INT_STATUS)
+               & P2A_INT_STS_ALL) != 0) {
+               for_each_set_bit(bit, &status, INTX_NUM) {
+                       /* clear interrupts */
+                       cra_writel(pcie, 1 << bit, P2A_INT_STATUS);
+
+                       virq = irq_find_mapping(pcie->irq_domain, bit + 1);
+                       if (virq)
+                               generic_handle_irq(virq);
+                       else
+                               dev_err(&pcie->pdev->dev,
+                                       "unexpected IRQ, INT%d\n", bit);
+               }
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void altera_pcie_release_of_pci_ranges(struct altera_pcie *pcie)
+{
+       pci_free_resource_list(&pcie->resources);
+}
+
+static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
+{
+       int err, res_valid = 0;
+       struct device *dev = &pcie->pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct resource_entry *win;
+
+       err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pcie->resources,
+                                              NULL);
+       if (err)
+               return err;
+
+       resource_list_for_each_entry(win, &pcie->resources) {
+               struct resource *parent, *res = win->res;
+
+               switch (resource_type(res)) {
+               case IORESOURCE_MEM:
+                       parent = &iomem_resource;
+                       res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+                       break;
+               default:
+                       continue;
+               }
+
+               err = devm_request_resource(dev, parent, res);
+               if (err)
+                       goto out_release_res;
+       }
+
+       if (!res_valid) {
+               dev_err(dev, "non-prefetchable memory resource required\n");
+               err = -EINVAL;
+               goto out_release_res;
+       }
+
+       return 0;
+
+out_release_res:
+       altera_pcie_release_of_pci_ranges(pcie);
+       return err;
+}
+
+static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+       struct device_node *node = dev->of_node;
+
+       /* Setup INTx */
+       pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM,
+                                       &intx_domain_ops, pcie);
+       if (!pcie->irq_domain) {
+               dev_err(dev, "Failed to get a INTx IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int altera_pcie_parse_dt(struct altera_pcie *pcie)
+{
+       struct resource *cra;
+       struct platform_device *pdev = pcie->pdev;
+
+       cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra");
+       if (!cra) {
+               dev_err(&pdev->dev, "no Cra memory resource defined\n");
+               return -ENODEV;
+       }
+
+       pcie->cra_base = devm_ioremap_resource(&pdev->dev, cra);
+       if (IS_ERR(pcie->cra_base)) {
+               dev_err(&pdev->dev, "failed to map cra memory\n");
+               return PTR_ERR(pcie->cra_base);
+       }
+
+       /* setup IRQ */
+       pcie->irq = platform_get_irq(pdev, 0);
+       if (pcie->irq <= 0) {
+               dev_err(&pdev->dev, "failed to get IRQ: %d\n", pcie->irq);
+               return -EINVAL;
+       }
+
+       irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie);
+
+       return 0;
+}
+
+static int altera_pcie_probe(struct platform_device *pdev)
+{
+       struct altera_pcie *pcie;
+       struct pci_bus *bus;
+       struct pci_bus *child;
+       int ret;
+
+       pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+       if (!pcie)
+               return -ENOMEM;
+
+       pcie->pdev = pdev;
+
+       ret = altera_pcie_parse_dt(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Parsing DT failed\n");
+               return ret;
+       }
+
+       INIT_LIST_HEAD(&pcie->resources);
+
+       ret = altera_pcie_parse_request_of_pci_ranges(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed add resources\n");
+               return ret;
+       }
+
+       ret = altera_pcie_init_irq_domain(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed creating IRQ Domain\n");
+               return ret;
+       }
+
+       /* clear all interrupts */
+       cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
+       /* enable all interrupts */
+       cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
+
+       bus = pci_scan_root_bus(&pdev->dev, pcie->root_bus_nr, &altera_pcie_ops,
+                               pcie, &pcie->resources);
+       if (!bus)
+               return -ENOMEM;
+
+       pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+       pci_assign_unassigned_bus_resources(bus);
+
+       /* Configure PCI Express setting. */
+       list_for_each_entry(child, &bus->children, node)
+               pcie_bus_configure_settings(child);
+
+       pci_bus_add_devices(bus);
+
+       platform_set_drvdata(pdev, pcie);
+       return ret;
+}
+
+static const struct of_device_id altera_pcie_of_match[] = {
+       { .compatible = "altr,pcie-root-port-1.0", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, altera_pcie_of_match);
+
+static struct platform_driver altera_pcie_driver = {
+       .probe          = altera_pcie_probe,
+       .driver = {
+               .name   = "altera-pcie",
+               .of_match_table = altera_pcie_of_match,
+               .suppress_bind_attrs = true,
+       },
+};
+
+static int altera_pcie_init(void)
+{
+       return platform_driver_register(&altera_pcie_driver);
+}
+module_init(altera_pcie_init);
+
+MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
+MODULE_DESCRIPTION("Altera PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
index 52aa6e34002bc2543f20b8607efdab9e2a5a669a..540f077c37eae7b59b983c31fa6ddce51d8bda6e 100644 (file)
@@ -35,7 +35,7 @@
 
 #define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
 #define PORT_LOGIC_SPEED_CHANGE                (0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK     (0x1ff << 8)
+#define PORT_LOGIC_LINK_WIDTH_MASK     (0x1f << 8)
 #define PORT_LOGIC_LINK_WIDTH_1_LANES  (0x1 << 8)
 #define PORT_LOGIC_LINK_WIDTH_2_LANES  (0x2 << 8)
 #define PORT_LOGIC_LINK_WIDTH_4_LANES  (0x4 << 8)
 #define PCIE_ATU_FUNC(x)               (((x) & 0x7) << 16)
 #define PCIE_ATU_UPPER_TARGET          0x91C
 
-static struct hw_pci dw_pci;
+static struct pci_ops dw_pcie_ops;
 
-static unsigned long global_io_offset;
-
-static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val)
 {
-       BUG_ON(!sys->private_data);
-
-       return sys->private_data;
-}
-
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
-{
-       *val = readl(addr);
+       if ((uintptr_t)addr & (size - 1)) {
+               *val = 0;
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
-       if (size == 1)
-               *val = (*val >> (8 * (where & 3))) & 0xff;
+       if (size == 4)
+               *val = readl(addr);
        else if (size == 2)
-               *val = (*val >> (8 * (where & 3))) & 0xffff;
-       else if (size != 4)
+               *val = readw(addr);
+       else if (size == 1)
+               *val = readb(addr);
+       else {
+               *val = 0;
                return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
 
        return PCIBIOS_SUCCESSFUL;
 }
 
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val)
 {
+       if ((uintptr_t)addr & (size - 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
        if (size == 4)
                writel(val, addr);
        else if (size == 2)
-               writew(val, addr + (where & 2));
+               writew(val, addr);
        else if (size == 1)
-               writeb(val, addr + (where & 3));
+               writeb(val, addr);
        else
                return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -132,8 +133,7 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
        if (pp->ops->rd_own_conf)
                ret = pp->ops->rd_own_conf(pp, where, size, val);
        else
-               ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
-                               size, val);
+               ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val);
 
        return ret;
 }
@@ -146,8 +146,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
        if (pp->ops->wr_own_conf)
                ret = pp->ops->wr_own_conf(pp, where, size, val);
        else
-               ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
-                               size, val);
+               ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
 
        return ret;
 }
@@ -205,12 +204,16 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
+       u64 msi_target;
+
        pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
+       msi_target = virt_to_phys((void *)pp->msi_data);
 
        /* program the msi_data */
        dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
-                       virt_to_phys((void *)pp->msi_data));
-       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
+                           (u32)(msi_target & 0xffffffff));
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
+                           (u32)(msi_target >> 32 & 0xffffffff));
 }
 
 static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
@@ -255,7 +258,7 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
        int irq, pos0, i;
-       struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(desc));
+       struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(desc);
 
        pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS,
                                       order_base_2(no_irqs));
@@ -286,6 +289,9 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
        }
 
        *pos = pos0;
+       desc->nvec_used = no_irqs;
+       desc->msi_attrib.multiple = order_base_2(no_irqs);
+
        return irq;
 
 no_valid_irq:
@@ -293,12 +299,32 @@ no_valid_irq:
        return -ENOSPC;
 }
 
+static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
+{
+       struct msi_msg msg;
+       u64 msi_target;
+
+       if (pp->ops->get_msi_addr)
+               msi_target = pp->ops->get_msi_addr(pp);
+       else
+               msi_target = virt_to_phys((void *)pp->msi_data);
+
+       msg.address_lo = (u32)(msi_target & 0xffffffff);
+       msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+
+       if (pp->ops->get_msi_data)
+               msg.data = pp->ops->get_msi_data(pp, pos);
+       else
+               msg.data = pos;
+
+       pci_write_msi_msg(irq, &msg);
+}
+
 static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
                        struct msi_desc *desc)
 {
        int irq, pos;
-       struct msi_msg msg;
-       struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+       struct pcie_port *pp = pdev->bus->sysdata;
 
        if (desc->msi_attrib.is_msix)
                return -EINVAL;
@@ -307,33 +333,50 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
        if (irq < 0)
                return irq;
 
-       if (pp->ops->get_msi_addr)
-               msg.address_lo = pp->ops->get_msi_addr(pp);
-       else
-               msg.address_lo = virt_to_phys((void *)pp->msi_data);
-       msg.address_hi = 0x0;
+       dw_msi_setup_msg(pp, irq, pos);
 
-       if (pp->ops->get_msi_data)
-               msg.data = pp->ops->get_msi_data(pp, pos);
-       else
-               msg.data = pos;
+       return 0;
+}
 
-       pci_write_msi_msg(irq, &msg);
+static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
+                            int nvec, int type)
+{
+#ifdef CONFIG_PCI_MSI
+       int irq, pos;
+       struct msi_desc *desc;
+       struct pcie_port *pp = pdev->bus->sysdata;
+
+       /* MSI-X interrupts are not supported */
+       if (type == PCI_CAP_ID_MSIX)
+               return -EINVAL;
+
+       WARN_ON(!list_is_singular(&pdev->dev.msi_list));
+       desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+
+       irq = assign_irq(nvec, desc, &pos);
+       if (irq < 0)
+               return irq;
+
+       dw_msi_setup_msg(pp, irq, pos);
 
        return 0;
+#else
+       return -EINVAL;
+#endif
 }
 
 static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
 {
        struct irq_data *data = irq_get_irq_data(irq);
        struct msi_desc *msi = irq_data_get_msi_desc(data);
-       struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+       struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
 
        clear_irq_range(pp, irq, 1, data->hwirq);
 }
 
 static struct msi_controller dw_pcie_msi_chip = {
        .setup_irq = dw_msi_setup_irq,
+       .setup_irqs = dw_msi_setup_irqs,
        .teardown_irq = dw_msi_teardown_irq,
 };
 
@@ -362,18 +405,12 @@ int dw_pcie_host_init(struct pcie_port *pp)
 {
        struct device_node *np = pp->dev->of_node;
        struct platform_device *pdev = to_platform_device(pp->dev);
-       struct of_pci_range range;
-       struct of_pci_range_parser parser;
+       struct pci_bus *bus, *child;
        struct resource *cfg_res;
-       u32 val, na, ns;
-       const __be32 *addrp;
-       int i, index, ret;
-
-       /* Find the address cell size and the number of cells in order to get
-        * the untranslated address.
-        */
-       of_property_read_u32(np, "#address-cells", &na);
-       ns = of_n_size_cells(np);
+       u32 val;
+       int i, ret;
+       LIST_HEAD(res);
+       struct resource_entry *win;
 
        cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
        if (cfg_res) {
@@ -381,88 +418,61 @@ int dw_pcie_host_init(struct pcie_port *pp)
                pp->cfg1_size = resource_size(cfg_res)/2;
                pp->cfg0_base = cfg_res->start;
                pp->cfg1_base = cfg_res->start + pp->cfg0_size;
-
-               /* Find the untranslated configuration space address */
-               index = of_property_match_string(np, "reg-names", "config");
-               addrp = of_get_address(np, index, NULL, NULL);
-               pp->cfg0_mod_base = of_read_number(addrp, ns);
-               pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size;
        } else if (!pp->va_cfg0_base) {
                dev_err(pp->dev, "missing *config* reg space\n");
        }
 
-       if (of_pci_range_parser_init(&parser, np)) {
-               dev_err(pp->dev, "missing ranges property\n");
-               return -EINVAL;
-       }
+       ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &pp->io_base);
+       if (ret)
+               return ret;
 
        /* Get the I/O and memory ranges from DT */
-       for_each_of_pci_range(&parser, &range) {
-               unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
-
-               if (restype == IORESOURCE_IO) {
-                       of_pci_range_to_resource(&range, np, &pp->io);
-                       pp->io.name = "I/O";
-                       pp->io.start = max_t(resource_size_t,
-                                            PCIBIOS_MIN_IO,
-                                            range.pci_addr + global_io_offset);
-                       pp->io.end = min_t(resource_size_t,
-                                          IO_SPACE_LIMIT,
-                                          range.pci_addr + range.size
-                                          + global_io_offset - 1);
-                       pp->io_size = resource_size(&pp->io);
-                       pp->io_bus_addr = range.pci_addr;
-                       pp->io_base = range.cpu_addr;
-
-                       /* Find the untranslated IO space address */
-                       pp->io_mod_base = of_read_number(parser.range -
-                                                        parser.np + na, ns);
-               }
-               if (restype == IORESOURCE_MEM) {
-                       of_pci_range_to_resource(&range, np, &pp->mem);
-                       pp->mem.name = "MEM";
-                       pp->mem_size = resource_size(&pp->mem);
-                       pp->mem_bus_addr = range.pci_addr;
-
-                       /* Find the untranslated MEM space address */
-                       pp->mem_mod_base = of_read_number(parser.range -
-                                                         parser.np + na, ns);
-               }
-               if (restype == 0) {
-                       of_pci_range_to_resource(&range, np, &pp->cfg);
-                       pp->cfg0_size = resource_size(&pp->cfg)/2;
-                       pp->cfg1_size = resource_size(&pp->cfg)/2;
-                       pp->cfg0_base = pp->cfg.start;
-                       pp->cfg1_base = pp->cfg.start + pp->cfg0_size;
-
-                       /* Find the untranslated configuration space address */
-                       pp->cfg0_mod_base = of_read_number(parser.range -
-                                                          parser.np + na, ns);
-                       pp->cfg1_mod_base = pp->cfg0_mod_base +
-                                           pp->cfg0_size;
+       resource_list_for_each_entry(win, &res) {
+               switch (resource_type(win->res)) {
+               case IORESOURCE_IO:
+                       pp->io = win->res;
+                       pp->io->name = "I/O";
+                       pp->io_size = resource_size(pp->io);
+                       pp->io_bus_addr = pp->io->start - win->offset;
+                       ret = pci_remap_iospace(pp->io, pp->io_base);
+                       if (ret) {
+                               dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
+                                        ret, pp->io);
+                               continue;
+                       }
+                       pp->io_base = pp->io->start;
+                       break;
+               case IORESOURCE_MEM:
+                       pp->mem = win->res;
+                       pp->mem->name = "MEM";
+                       pp->mem_size = resource_size(pp->mem);
+                       pp->mem_bus_addr = pp->mem->start - win->offset;
+                       break;
+               case 0:
+                       pp->cfg = win->res;
+                       pp->cfg0_size = resource_size(pp->cfg)/2;
+                       pp->cfg1_size = resource_size(pp->cfg)/2;
+                       pp->cfg0_base = pp->cfg->start;
+                       pp->cfg1_base = pp->cfg->start + pp->cfg0_size;
+                       break;
+               case IORESOURCE_BUS:
+                       pp->busn = win->res;
+                       break;
+               default:
+                       continue;
                }
        }
 
-       ret = of_pci_parse_bus_range(np, &pp->busn);
-       if (ret < 0) {
-               pp->busn.name = np->name;
-               pp->busn.start = 0;
-               pp->busn.end = 0xff;
-               pp->busn.flags = IORESOURCE_BUS;
-               dev_dbg(pp->dev, "failed to parse bus-range property: %d, using default %pR\n",
-                       ret, &pp->busn);
-       }
-
        if (!pp->dbi_base) {
-               pp->dbi_base = devm_ioremap(pp->dev, pp->cfg.start,
-                                       resource_size(&pp->cfg));
+               pp->dbi_base = devm_ioremap(pp->dev, pp->cfg->start,
+                                       resource_size(pp->cfg));
                if (!pp->dbi_base) {
                        dev_err(pp->dev, "error with ioremap\n");
                        return -ENOMEM;
                }
        }
 
-       pp->mem_base = pp->mem.start;
+       pp->mem_base = pp->mem->start;
 
        if (!pp->va_cfg0_base) {
                pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
@@ -482,10 +492,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
-               dev_err(pp->dev, "Failed to parse the number of lanes\n");
-               return -EINVAL;
-       }
+       ret = of_property_read_u32(np, "num-lanes", &pp->lanes);
+       if (ret)
+               pp->lanes = 0;
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                if (!pp->ops->msi_host_init) {
@@ -511,7 +520,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
        if (!pp->ops->rd_other_conf)
                dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
-                                         PCIE_ATU_TYPE_MEM, pp->mem_mod_base,
+                                         PCIE_ATU_TYPE_MEM, pp->mem_base,
                                          pp->mem_bus_addr, pp->mem_size);
 
        dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
@@ -523,15 +532,35 @@ int dw_pcie_host_init(struct pcie_port *pp)
        val |= PORT_LOGIC_SPEED_CHANGE;
        dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
 
-#ifdef CONFIG_PCI_MSI
-       dw_pcie_msi_chip.dev = pp->dev;
+       pp->root_bus_nr = pp->busn->start;
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr,
+                                           &dw_pcie_ops, pp, &res,
+                                           &dw_pcie_msi_chip);
+               dw_pcie_msi_chip.dev = pp->dev;
+       } else
+               bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
+                                       pp, &res);
+       if (!bus)
+               return -ENOMEM;
+
+       if (pp->ops->scan_bus)
+               pp->ops->scan_bus(pp);
+
+#ifdef CONFIG_ARM
+       /* support old dtbs that incorrectly describe IRQs */
+       pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
 #endif
 
-       dw_pci.nr_controllers = 1;
-       dw_pci.private_data = (void **)&pp;
+       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_size_bridges(bus);
+               pci_bus_assign_resources(bus);
 
-       pci_common_init_dev(pp->dev, &dw_pci);
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child);
+       }
 
+       pci_bus_add_devices(bus);
        return 0;
 }
 
@@ -539,22 +568,21 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
                u32 devfn, int where, int size, u32 *val)
 {
        int ret, type;
-       u32 address, busdev, cfg_size;
+       u32 busdev, cfg_size;
        u64 cpu_addr;
        void __iomem *va_cfg_base;
 
        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-       address = where & ~0x3;
 
        if (bus->parent->number == pp->root_bus_nr) {
                type = PCIE_ATU_TYPE_CFG0;
-               cpu_addr = pp->cfg0_mod_base;
+               cpu_addr = pp->cfg0_base;
                cfg_size = pp->cfg0_size;
                va_cfg_base = pp->va_cfg0_base;
        } else {
                type = PCIE_ATU_TYPE_CFG1;
-               cpu_addr = pp->cfg1_mod_base;
+               cpu_addr = pp->cfg1_base;
                cfg_size = pp->cfg1_size;
                va_cfg_base = pp->va_cfg1_base;
        }
@@ -562,9 +590,9 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  type, cpu_addr,
                                  busdev, cfg_size);
-       ret = dw_pcie_cfg_read(va_cfg_base + address, where, size, val);
+       ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-                                 PCIE_ATU_TYPE_IO, pp->io_mod_base,
+                                 PCIE_ATU_TYPE_IO, pp->io_base,
                                  pp->io_bus_addr, pp->io_size);
 
        return ret;
@@ -574,22 +602,21 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
                u32 devfn, int where, int size, u32 val)
 {
        int ret, type;
-       u32 address, busdev, cfg_size;
+       u32 busdev, cfg_size;
        u64 cpu_addr;
        void __iomem *va_cfg_base;
 
        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-       address = where & ~0x3;
 
        if (bus->parent->number == pp->root_bus_nr) {
                type = PCIE_ATU_TYPE_CFG0;
-               cpu_addr = pp->cfg0_mod_base;
+               cpu_addr = pp->cfg0_base;
                cfg_size = pp->cfg0_size;
                va_cfg_base = pp->va_cfg0_base;
        } else {
                type = PCIE_ATU_TYPE_CFG1;
-               cpu_addr = pp->cfg1_mod_base;
+               cpu_addr = pp->cfg1_base;
                cfg_size = pp->cfg1_size;
                va_cfg_base = pp->va_cfg1_base;
        }
@@ -597,9 +624,9 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
                                  type, cpu_addr,
                                  busdev, cfg_size);
-       ret = dw_pcie_cfg_write(va_cfg_base + address, where, size, val);
+       ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
        dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
-                                 PCIE_ATU_TYPE_IO, pp->io_mod_base,
+                                 PCIE_ATU_TYPE_IO, pp->io_base,
                                  pp->io_bus_addr, pp->io_size);
 
        return ret;
@@ -631,7 +658,7 @@ static int dw_pcie_valid_config(struct pcie_port *pp,
 static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
                        int size, u32 *val)
 {
-       struct pcie_port *pp = sys_to_pcie(bus->sysdata);
+       struct pcie_port *pp = bus->sysdata;
        int ret;
 
        if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
@@ -655,7 +682,7 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
                        int where, int size, u32 val)
 {
-       struct pcie_port *pp = sys_to_pcie(bus->sysdata);
+       struct pcie_port *pp = bus->sysdata;
        int ret;
 
        if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
@@ -679,69 +706,6 @@ static struct pci_ops dw_pcie_ops = {
        .write = dw_pcie_wr_conf,
 };
 
-static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
-{
-       struct pcie_port *pp;
-
-       pp = sys_to_pcie(sys);
-
-       if (global_io_offset < SZ_1M && pp->io_size > 0) {
-               sys->io_offset = global_io_offset - pp->io_bus_addr;
-               pci_ioremap_io(global_io_offset, pp->io_base);
-               global_io_offset += SZ_64K;
-               pci_add_resource_offset(&sys->resources, &pp->io,
-                                       sys->io_offset);
-       }
-
-       sys->mem_offset = pp->mem.start - pp->mem_bus_addr;
-       pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset);
-       pci_add_resource(&sys->resources, &pp->busn);
-
-       return 1;
-}
-
-static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
-{
-       struct pci_bus *bus;
-       struct pcie_port *pp = sys_to_pcie(sys);
-
-       pp->root_bus_nr = sys->busnr;
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               bus = pci_scan_root_bus_msi(pp->dev, sys->busnr, &dw_pcie_ops,
-                                           sys, &sys->resources,
-                                           &dw_pcie_msi_chip);
-       else
-               bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops,
-                                       sys, &sys->resources);
-
-       if (!bus)
-               return NULL;
-
-       if (bus && pp->ops->scan_bus)
-               pp->ops->scan_bus(pp);
-
-       return bus;
-}
-
-static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
-       int irq;
-
-       irq = of_irq_parse_and_map_pci(dev, slot, pin);
-       if (!irq)
-               irq = pp->irq;
-
-       return irq;
-}
-
-static struct hw_pci dw_pci = {
-       .setup          = dw_pcie_setup,
-       .scan           = dw_pcie_scan_bus,
-       .map_irq        = dw_pcie_map_irq,
-};
-
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
        u32 val;
@@ -764,6 +728,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        case 8:
                val |= PORT_LINK_MODE_8_LANES;
                break;
+       default:
+               dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes);
+               return;
        }
        dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
 
index d0bbd276840dfcac4e7a66ba7ca7ad1f7a623e6e..2356d29e8527e71062d4fd5addb9f0ac55652b46 100644 (file)
@@ -27,25 +27,21 @@ struct pcie_port {
        u8                      root_bus_nr;
        void __iomem            *dbi_base;
        u64                     cfg0_base;
-       u64                     cfg0_mod_base;
        void __iomem            *va_cfg0_base;
        u32                     cfg0_size;
        u64                     cfg1_base;
-       u64                     cfg1_mod_base;
        void __iomem            *va_cfg1_base;
        u32                     cfg1_size;
-       u64                     io_base;
-       u64                     io_mod_base;
+       resource_size_t         io_base;
        phys_addr_t             io_bus_addr;
        u32                     io_size;
        u64                     mem_base;
-       u64                     mem_mod_base;
        phys_addr_t             mem_bus_addr;
        u32                     mem_size;
-       struct resource         cfg;
-       struct resource         io;
-       struct resource         mem;
-       struct resource         busn;
+       struct resource         *cfg;
+       struct resource         *io;
+       struct resource         *mem;
+       struct resource         *busn;
        int                     irq;
        u32                     lanes;
        struct pcie_host_ops    *ops;
@@ -70,14 +66,14 @@ struct pcie_host_ops {
        void (*host_init)(struct pcie_port *pp);
        void (*msi_set_irq)(struct pcie_port *pp, int irq);
        void (*msi_clear_irq)(struct pcie_port *pp, int irq);
-       u32 (*get_msi_addr)(struct pcie_port *pp);
+       phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
        u32 (*get_msi_data)(struct pcie_port *pp, int pos);
        void (*scan_bus)(struct pcie_port *pp);
        int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
 };
 
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val);
+int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c
new file mode 100644 (file)
index 0000000..35457ec
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * PCIe host controller driver for HiSilicon Hip05 SoC
+ *
+ * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.com
+ *
+ * Author: Zhou Wang <wangzhou1@hisilicon.com>
+ *         Dacai Zhu <zhudacai@hisilicon.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/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "pcie-designware.h"
+
+#define PCIE_SUBCTRL_SYS_STATE4_REG                     0x6818
+#define PCIE_LTSSM_LINKUP_STATE                         0x11
+#define PCIE_LTSSM_STATE_MASK                           0x3F
+
+#define to_hisi_pcie(x)        container_of(x, struct hisi_pcie, pp)
+
+struct hisi_pcie {
+       struct regmap *subctrl;
+       void __iomem *reg_base;
+       u32 port_id;
+       struct pcie_port pp;
+};
+
+static inline void hisi_pcie_apb_writel(struct hisi_pcie *pcie,
+                                       u32 val, u32 reg)
+{
+       writel(val, pcie->reg_base + reg);
+}
+
+static inline u32 hisi_pcie_apb_readl(struct hisi_pcie *pcie, u32 reg)
+{
+       return readl(pcie->reg_base + reg);
+}
+
+/* Hip05 PCIe host only supports 32-bit config access */
+static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
+                             u32 *val)
+{
+       u32 reg;
+       u32 reg_val;
+       struct hisi_pcie *pcie = to_hisi_pcie(pp);
+       void *walker = &reg_val;
+
+       walker += (where & 0x3);
+       reg = where & ~0x3;
+       reg_val = hisi_pcie_apb_readl(pcie, reg);
+
+       if (size == 1)
+               *val = *(u8 __force *) walker;
+       else if (size == 2)
+               *val = *(u16 __force *) walker;
+       else if (size != 4)
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+/* Hip05 PCIe host only supports 32-bit config access */
+static int hisi_pcie_cfg_write(struct pcie_port *pp, int where, int  size,
+                               u32 val)
+{
+       u32 reg_val;
+       u32 reg;
+       struct hisi_pcie *pcie = to_hisi_pcie(pp);
+       void *walker = &reg_val;
+
+       walker += (where & 0x3);
+       reg = where & ~0x3;
+       if (size == 4)
+               hisi_pcie_apb_writel(pcie, val, reg);
+       else if (size == 2) {
+               reg_val = hisi_pcie_apb_readl(pcie, reg);
+               *(u16 __force *) walker = val;
+               hisi_pcie_apb_writel(pcie, reg_val, reg);
+       } else if (size == 1) {
+               reg_val = hisi_pcie_apb_readl(pcie, reg);
+               *(u8 __force *) walker = val;
+               hisi_pcie_apb_writel(pcie, reg_val, reg);
+       } else
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int hisi_pcie_link_up(struct pcie_port *pp)
+{
+       u32 val;
+       struct hisi_pcie *hisi_pcie = to_hisi_pcie(pp);
+
+       regmap_read(hisi_pcie->subctrl, PCIE_SUBCTRL_SYS_STATE4_REG +
+                   0x100 * hisi_pcie->port_id, &val);
+
+       return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE);
+}
+
+static struct pcie_host_ops hisi_pcie_host_ops = {
+       .rd_own_conf = hisi_pcie_cfg_read,
+       .wr_own_conf = hisi_pcie_cfg_write,
+       .link_up = hisi_pcie_link_up,
+};
+
+static int __init hisi_add_pcie_port(struct pcie_port *pp,
+                                    struct platform_device *pdev)
+{
+       int ret;
+       u32 port_id;
+       struct hisi_pcie *hisi_pcie = to_hisi_pcie(pp);
+
+       if (of_property_read_u32(pdev->dev.of_node, "port-id", &port_id)) {
+               dev_err(&pdev->dev, "failed to read port-id\n");
+               return -EINVAL;
+       }
+       if (port_id > 3) {
+               dev_err(&pdev->dev, "Invalid port-id: %d\n", port_id);
+               return -EINVAL;
+       }
+       hisi_pcie->port_id = port_id;
+
+       pp->ops = &hisi_pcie_host_ops;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __init hisi_pcie_probe(struct platform_device *pdev)
+{
+       struct hisi_pcie *hisi_pcie;
+       struct pcie_port *pp;
+       struct resource *reg;
+       int ret;
+
+       hisi_pcie = devm_kzalloc(&pdev->dev, sizeof(*hisi_pcie), GFP_KERNEL);
+       if (!hisi_pcie)
+               return -ENOMEM;
+
+       pp = &hisi_pcie->pp;
+       pp->dev = &pdev->dev;
+
+       hisi_pcie->subctrl =
+       syscon_regmap_lookup_by_compatible("hisilicon,pcie-sas-subctrl");
+       if (IS_ERR(hisi_pcie->subctrl)) {
+               dev_err(pp->dev, "cannot get subctrl base\n");
+               return PTR_ERR(hisi_pcie->subctrl);
+       }
+
+       reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbi");
+       hisi_pcie->reg_base = devm_ioremap_resource(&pdev->dev, reg);
+       if (IS_ERR(hisi_pcie->reg_base)) {
+               dev_err(pp->dev, "cannot get rc_dbi base\n");
+               return PTR_ERR(hisi_pcie->reg_base);
+       }
+
+       hisi_pcie->pp.dbi_base = hisi_pcie->reg_base;
+
+       ret = hisi_add_pcie_port(pp, pdev);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, hisi_pcie);
+
+       dev_warn(pp->dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n");
+
+       return 0;
+}
+
+static const struct of_device_id hisi_pcie_of_match[] = {
+       {.compatible = "hisilicon,hip05-pcie",},
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, hisi_pcie_of_match);
+
+static struct platform_driver hisi_pcie_driver = {
+       .probe  = hisi_pcie_probe,
+       .driver = {
+                  .name = "hisi-pcie",
+                  .of_match_table = hisi_pcie_of_match,
+       },
+};
+
+module_platform_driver(hisi_pcie_driver);
index 9aedc8eb2c6eaa3ffcb29dc562171f9a75161e52..c9550dc8b8ed4b8fc330d1d21cefed43989db030 100644 (file)
@@ -54,6 +54,33 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       if (of_property_read_bool(np, "brcm,pcie-ob")) {
+               u32 val;
+
+               ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset",
+                                          &val);
+               if (ret) {
+                       dev_err(pcie->dev,
+                               "missing brcm,pcie-ob-axi-offset property\n");
+                       return ret;
+               }
+               pcie->ob.axi_offset = val;
+
+               ret = of_property_read_u32(np, "brcm,pcie-ob-window-size",
+                                          &val);
+               if (ret) {
+                       dev_err(pcie->dev,
+                               "missing brcm,pcie-ob-window-size property\n");
+                       return ret;
+               }
+               pcie->ob.window_size = (resource_size_t)val * SZ_1M;
+
+               if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size"))
+                       pcie->ob.set_oarr_size = true;
+
+               pcie->need_ob_cfg = true;
+       }
+
        /* PHY use is optional */
        pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy");
        if (IS_ERR(pcie->phy)) {
index fe2efb141a9bd3b74c22af5764ead81dcfc2ce6d..eac719af16aa835fa61f8ee96cd5c87ee737d520 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
- * Copyright (C) 2015 Broadcom Corporatcommon ion
+ * Copyright (C) 2015 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -31,6 +31,8 @@
 #include "pcie-iproc.h"
 
 #define CLK_CONTROL_OFFSET           0x000
+#define EP_PERST_SOURCE_SELECT_SHIFT 2
+#define EP_PERST_SOURCE_SELECT       BIT(EP_PERST_SOURCE_SELECT_SHIFT)
 #define EP_MODE_SURVIVE_PERST_SHIFT  1
 #define EP_MODE_SURVIVE_PERST        BIT(EP_MODE_SURVIVE_PERST_SHIFT)
 #define RC_PCIE_RST_OUTPUT_SHIFT     0
 #define SYS_RC_INTX_EN               0x330
 #define SYS_RC_INTX_MASK             0xf
 
+#define PCIE_LINK_STATUS_OFFSET      0xf0c
+#define PCIE_PHYLINKUP_SHIFT         3
+#define PCIE_PHYLINKUP               BIT(PCIE_PHYLINKUP_SHIFT)
+#define PCIE_DL_ACTIVE_SHIFT         2
+#define PCIE_DL_ACTIVE               BIT(PCIE_DL_ACTIVE_SHIFT)
+
+#define OARR_VALID_SHIFT             0
+#define OARR_VALID                   BIT(OARR_VALID_SHIFT)
+#define OARR_SIZE_CFG_SHIFT          1
+#define OARR_SIZE_CFG                BIT(OARR_SIZE_CFG_SHIFT)
+
+#define OARR_LO(window)              (0xd20 + (window) * 8)
+#define OARR_HI(window)              (0xd24 + (window) * 8)
+#define OMAP_LO(window)              (0xd40 + (window) * 8)
+#define OMAP_HI(window)              (0xd44 + (window) * 8)
+
+#define MAX_NUM_OB_WINDOWS           2
+
 static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
 {
        struct iproc_pcie *pcie;
@@ -119,23 +139,32 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie)
        u32 val;
 
        /*
-        * Configure the PCIe controller as root complex and send a downstream
-        * reset
+        * Select perst_b signal as reset source. Put the device into reset,
+        * and then bring it out of reset
         */
-       val = EP_MODE_SURVIVE_PERST | RC_PCIE_RST_OUTPUT;
+       val = readl(pcie->base + CLK_CONTROL_OFFSET);
+       val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
+               ~RC_PCIE_RST_OUTPUT;
        writel(val, pcie->base + CLK_CONTROL_OFFSET);
        udelay(250);
-       val &= ~EP_MODE_SURVIVE_PERST;
+
+       val |= RC_PCIE_RST_OUTPUT;
        writel(val, pcie->base + CLK_CONTROL_OFFSET);
-       msleep(250);
+       msleep(100);
 }
 
 static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
 {
        u8 hdr_type;
-       u32 link_ctrl;
+       u32 link_ctrl, class, val;
        u16 pos, link_status;
-       int link_is_active = 0;
+       bool link_is_active = false;
+
+       val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET);
+       if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) {
+               dev_err(pcie->dev, "PHY or data link is INACTIVE!\n");
+               return -ENODEV;
+       }
 
        /* make sure we are not in EP mode */
        pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type);
@@ -145,14 +174,19 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
        }
 
        /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
-       pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE,
-                                 PCI_CLASS_BRIDGE_PCI);
+#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
+#define PCI_CLASS_BRIDGE_MASK      0xffff00
+#define PCI_CLASS_BRIDGE_SHIFT     8
+       pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class);
+       class &= ~PCI_CLASS_BRIDGE_MASK;
+       class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
+       pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class);
 
        /* check link status to see if link is active */
        pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP);
        pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status);
        if (link_status & PCI_EXP_LNKSTA_NLW)
-               link_is_active = 1;
+               link_is_active = true;
 
        if (!link_is_active) {
                /* try GEN 1 link speed */
@@ -176,7 +210,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus)
                        pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA,
                                                 &link_status);
                        if (link_status & PCI_EXP_LNKSTA_NLW)
-                               link_is_active = 1;
+                               link_is_active = true;
                }
        }
 
@@ -190,6 +224,101 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie)
        writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
 }
 
+/**
+ * Some iProc SoCs require the SW to configure the outbound address mapping
+ *
+ * Outbound address translation:
+ *
+ * iproc_pcie_address = axi_address - axi_offset
+ * OARR = iproc_pcie_address
+ * OMAP = pci_addr
+ *
+ * axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address
+ */
+static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
+                              u64 pci_addr, resource_size_t size)
+{
+       struct iproc_pcie_ob *ob = &pcie->ob;
+       unsigned i;
+       u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS;
+       u64 remainder;
+
+       if (size > max_size) {
+               dev_err(pcie->dev,
+                       "res size 0x%pap exceeds max supported size 0x%llx\n",
+                       &size, max_size);
+               return -EINVAL;
+       }
+
+       div64_u64_rem(size, ob->window_size, &remainder);
+       if (remainder) {
+               dev_err(pcie->dev,
+                       "res size %pap needs to be multiple of window size %pap\n",
+                       &size, &ob->window_size);
+               return -EINVAL;
+       }
+
+       if (axi_addr < ob->axi_offset) {
+               dev_err(pcie->dev,
+                       "axi address %pap less than offset %pap\n",
+                       &axi_addr, &ob->axi_offset);
+               return -EINVAL;
+       }
+
+       /*
+        * Translate the AXI address to the internal address used by the iProc
+        * PCIe core before programming the OARR
+        */
+       axi_addr -= ob->axi_offset;
+
+       for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) {
+               writel(lower_32_bits(axi_addr) | OARR_VALID |
+                      (ob->set_oarr_size ? 1 : 0), pcie->base + OARR_LO(i));
+               writel(upper_32_bits(axi_addr), pcie->base + OARR_HI(i));
+               writel(lower_32_bits(pci_addr), pcie->base + OMAP_LO(i));
+               writel(upper_32_bits(pci_addr), pcie->base + OMAP_HI(i));
+
+               size -= ob->window_size;
+               if (size == 0)
+                       break;
+
+               axi_addr += ob->window_size;
+               pci_addr += ob->window_size;
+       }
+
+       return 0;
+}
+
+static int iproc_pcie_map_ranges(struct iproc_pcie *pcie,
+                                struct list_head *resources)
+{
+       struct resource_entry *window;
+       int ret;
+
+       resource_list_for_each_entry(window, resources) {
+               struct resource *res = window->res;
+               u64 res_type = resource_type(res);
+
+               switch (res_type) {
+               case IORESOURCE_IO:
+               case IORESOURCE_BUS:
+                       break;
+               case IORESOURCE_MEM:
+                       ret = iproc_pcie_setup_ob(pcie, res->start,
+                                                 res->start - window->offset,
+                                                 resource_size(res));
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       dev_err(pcie->dev, "invalid resource %pR\n", res);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 {
        int ret;
@@ -213,6 +342,14 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 
        iproc_pcie_reset(pcie);
 
+       if (pcie->need_ob_cfg) {
+               ret = iproc_pcie_map_ranges(pcie, res);
+               if (ret) {
+                       dev_err(pcie->dev, "map failed\n");
+                       goto err_power_off_phy;
+               }
+       }
+
 #ifdef CONFIG_ARM
        pcie->sysdata.private_data = pcie;
        sysdata = &pcie->sysdata;
@@ -238,9 +375,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
 
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
-#ifdef CONFIG_ARM
        pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
-#endif
        pci_bus_add_devices(bus);
 
        return 0;
index c9e4c10a462e80897eafec3fbbf3ba119c2307e3..d3dc940f773a2279d13ad295bc9bd70a86638d23 100644 (file)
 #ifndef _PCIE_IPROC_H
 #define _PCIE_IPROC_H
 
-#define IPROC_PCIE_MAX_NUM_IRQS 6
+/**
+ * iProc PCIe outbound mapping
+ * @set_oarr_size: indicates the OARR size bit needs to be set
+ * @axi_offset: offset from the AXI address to the internal address used by
+ * the iProc PCIe core
+ * @window_size: outbound window size
+ */
+struct iproc_pcie_ob {
+       bool set_oarr_size;
+       resource_size_t axi_offset;
+       resource_size_t window_size;
+};
 
 /**
  * iProc PCIe device
  * @dev: pointer to device data structure
  * @base: PCIe host controller I/O register base
- * @resources: linked list of all PCI resources
  * @sysdata: Per PCI controller data (ARM-specific)
  * @root_bus: pointer to root bus
  * @phy: optional PHY device that controls the Serdes
  * @irqs: interrupt IDs
+ * @map_irq: function callback to map interrupts
+ * @need_ob_cfg: indidates SW needs to configure the outbound mapping window
+ * @ob: outbound mapping parameters
  */
 struct iproc_pcie {
        struct device *dev;
@@ -34,8 +47,9 @@ struct iproc_pcie {
 #endif
        struct pci_bus *root_bus;
        struct phy *phy;
-       int irqs[IPROC_PCIE_MAX_NUM_IRQS];
        int (*map_irq)(const struct pci_dev *, u8, u8);
+       bool need_ob_cfg;
+       struct iproc_pcie_ob ob;
 };
 
 int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
index 7678fe0820d712d00fe189e8bf3d0651d4277ae9..f4fa6c537448cae9d25519a8697e212aa70facaa 100644 (file)
 #define RCAR_PCI_MAX_RESOURCES 4
 #define MAX_NR_INBOUND_MAPS 6
 
+static unsigned long global_io_offset;
+
 struct rcar_msi {
        DECLARE_BITMAP(used, INT_PCI_MSI_NR);
        struct irq_domain *domain;
@@ -124,7 +126,16 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
 }
 
 /* Structure representing the PCIe interface */
+/*
+ * ARM pcibios functions expect the ARM struct pci_sys_data as the PCI
+ * sysdata.  Add pci_sys_data as the first element in struct gen_pci so
+ * that when we use a gen_pci pointer as sysdata, it is also a pointer to
+ * a struct pci_sys_data.
+ */
 struct rcar_pcie {
+#ifdef CONFIG_ARM
+       struct pci_sys_data     sys;
+#endif
        struct device           *dev;
        void __iomem            *base;
        struct resource         res[RCAR_PCI_MAX_RESOURCES];
@@ -135,11 +146,6 @@ struct rcar_pcie {
        struct                  rcar_msi msi;
 };
 
-static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
-{
-       return sys->private_data;
-}
-
 static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
                               unsigned long reg)
 {
@@ -258,7 +264,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
 static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
                               int where, int size, u32 *val)
 {
-       struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+       struct rcar_pcie *pcie = bus->sysdata;
        int ret;
 
        ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ,
@@ -283,7 +289,7 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
 static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
                                int where, int size, u32 val)
 {
-       struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+       struct rcar_pcie *pcie = bus->sysdata;
        int shift, ret;
        u32 data;
 
@@ -353,13 +359,12 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie)
        rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win));
 }
 
-static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
+static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pcie)
 {
-       struct rcar_pcie *pcie = sys_to_pcie(sys);
        struct resource *res;
        int i;
 
-       pcie->root_bus_nr = -1;
+       pcie->root_bus_nr = pcie->busn.start;
 
        /* Setup PCI resources */
        for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) {
@@ -372,32 +377,53 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
 
                if (res->flags & IORESOURCE_IO) {
                        phys_addr_t io_start = pci_pio_to_address(res->start);
-                       pci_ioremap_io(nr * SZ_64K, io_start);
-               } else
-                       pci_add_resource(&sys->resources, res);
+                       pci_ioremap_io(global_io_offset, io_start);
+                       global_io_offset += SZ_64K;
+               }
+
+               pci_add_resource(resource, res);
        }
-       pci_add_resource(&sys->resources, &pcie->busn);
+       pci_add_resource(resource, &pcie->busn);
 
        return 1;
 }
 
-static struct hw_pci rcar_pci = {
-       .setup          = rcar_pcie_setup,
-       .map_irq        = of_irq_parse_and_map_pci,
-       .ops            = &rcar_pcie_ops,
-};
-
-static void rcar_pcie_enable(struct rcar_pcie *pcie)
+static int rcar_pcie_enable(struct rcar_pcie *pcie)
 {
-       struct platform_device *pdev = to_platform_device(pcie->dev);
+       struct pci_bus *bus, *child;
+       LIST_HEAD(res);
 
-       rcar_pci.nr_controllers = 1;
-       rcar_pci.private_data = (void **)&pcie;
-#ifdef CONFIG_PCI_MSI
-       rcar_pci.msi_ctrl = &pcie->msi.chip;
-#endif
+       rcar_pcie_setup(&res, pcie);
+
+       /* Do not reassign resources if probe only */
+       if (!pci_has_flag(PCI_PROBE_ONLY))
+               pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
 
-       pci_common_init_dev(&pdev->dev, &rcar_pci);
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr,
+                               &rcar_pcie_ops, pcie, &res, &pcie->msi.chip);
+       else
+               bus = pci_scan_root_bus(pcie->dev, pcie->root_bus_nr,
+                               &rcar_pcie_ops, pcie, &res);
+
+       if (!bus) {
+               dev_err(pcie->dev, "Scanning rootbus failed");
+               return -ENODEV;
+       }
+
+       pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+
+       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_size_bridges(bus);
+               pci_bus_assign_resources(bus);
+
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child);
+       }
+
+       pci_bus_add_devices(bus);
+
+       return 0;
 }
 
 static int phy_wait_for_ack(struct rcar_pcie *pcie)
@@ -970,9 +996,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
        data = rcar_pci_read_reg(pcie, MACSR);
        dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
 
-       rcar_pcie_enable(pcie);
-
-       return 0;
+       return rcar_pcie_enable(pcie);
 }
 
 static struct platform_driver rcar_pcie_driver = {
index 98d2683181bc5fbbbff05b89170d864c02e12cb3..b95b7563c052135bbad5407073685d9ff8930df6 100644 (file)
@@ -163,34 +163,34 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
         * default value in capability register is 512 bytes. So force
         * it to 128 here.
         */
-       dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val);
+       dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
        val &= ~PCI_EXP_DEVCTL_READRQ;
-       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val);
+       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
 
-       dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A);
-       dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80);
+       dw_pcie_cfg_write(pp->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
+       dw_pcie_cfg_write(pp->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
 
        /*
         * if is_gen1 is set then handle it, so that some buggy card
         * also works
         */
        if (spear13xx_pcie->is_gen1) {
-               dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4,
-                                &val);
+               dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
+                                       4, &val);
                if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
                        val &= ~((u32)PCI_EXP_LNKCAP_SLS);
                        val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-                                         PCI_EXP_LNKCAP, 4, val);
+                       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+                               PCI_EXP_LNKCAP, 4, val);
                }
 
-               dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4,
-                                &val);
+               dw_pcie_cfg_read(pp->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
+                                       2, &val);
                if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
                        val &= ~((u32)PCI_EXP_LNKCAP_SLS);
                        val |= PCI_EXP_LNKCAP_SLS_2_5GB;
-                       dw_pcie_cfg_write(pp->dbi_base, exp_cap_off +
-                                         PCI_EXP_LNKCTL2, 4, val);
+                       dw_pcie_cfg_write(pp->dbi_base + exp_cap_off +
+                                       PCI_EXP_LNKCTL2, 2, val);
                }
        }
 
index f3796124ad7cc9b5076ef2990d0a87b08bf5c94c..4c8f4cde68540933e0a7c83ac8011bfd68d561e7 100644 (file)
@@ -204,36 +204,39 @@ static void pciehp_power_thread(struct work_struct *work)
        kfree(info);
 }
 
-void pciehp_queue_pushbutton_work(struct work_struct *work)
+static void pciehp_queue_power_work(struct slot *p_slot, int req)
 {
-       struct slot *p_slot = container_of(work, struct slot, work.work);
        struct power_work_info *info;
 
+       p_slot->state = (req == ENABLE_REQ) ? POWERON_STATE : POWEROFF_STATE;
+
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
-                        __func__);
+               ctrl_err(p_slot->ctrl, "no memory to queue %s request\n",
+                        (req == ENABLE_REQ) ? "poweron" : "poweroff");
                return;
        }
        info->p_slot = p_slot;
        INIT_WORK(&info->work, pciehp_power_thread);
+       info->req = req;
+       queue_work(p_slot->wq, &info->work);
+}
+
+void pciehp_queue_pushbutton_work(struct work_struct *work)
+{
+       struct slot *p_slot = container_of(work, struct slot, work.work);
 
        mutex_lock(&p_slot->lock);
        switch (p_slot->state) {
        case BLINKINGOFF_STATE:
-               p_slot->state = POWEROFF_STATE;
-               info->req = DISABLE_REQ;
+               pciehp_queue_power_work(p_slot, DISABLE_REQ);
                break;
        case BLINKINGON_STATE:
-               p_slot->state = POWERON_STATE;
-               info->req = ENABLE_REQ;
+               pciehp_queue_power_work(p_slot, ENABLE_REQ);
                break;
        default:
-               kfree(info);
-               goto out;
+               break;
        }
-       queue_work(p_slot->wq, &info->work);
- out:
        mutex_unlock(&p_slot->lock);
 }
 
@@ -301,27 +304,12 @@ static void handle_button_press_event(struct slot *p_slot)
 static void handle_surprise_event(struct slot *p_slot)
 {
        u8 getstatus;
-       struct power_work_info *info;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
-                        __func__);
-               return;
-       }
-       info->p_slot = p_slot;
-       INIT_WORK(&info->work, pciehp_power_thread);
 
        pciehp_get_adapter_status(p_slot, &getstatus);
-       if (!getstatus) {
-               p_slot->state = POWEROFF_STATE;
-               info->req = DISABLE_REQ;
-       } else {
-               p_slot->state = POWERON_STATE;
-               info->req = ENABLE_REQ;
-       }
-
-       queue_work(p_slot->wq, &info->work);
+       if (!getstatus)
+               pciehp_queue_power_work(p_slot, DISABLE_REQ);
+       else
+               pciehp_queue_power_work(p_slot, ENABLE_REQ);
 }
 
 /*
@@ -330,17 +318,6 @@ static void handle_surprise_event(struct slot *p_slot)
 static void handle_link_event(struct slot *p_slot, u32 event)
 {
        struct controller *ctrl = p_slot->ctrl;
-       struct power_work_info *info;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
-                        __func__);
-               return;
-       }
-       info->p_slot = p_slot;
-       info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
-       INIT_WORK(&info->work, pciehp_power_thread);
 
        switch (p_slot->state) {
        case BLINKINGON_STATE:
@@ -348,22 +325,19 @@ static void handle_link_event(struct slot *p_slot, u32 event)
                cancel_delayed_work(&p_slot->work);
                /* Fall through */
        case STATIC_STATE:
-               p_slot->state = event == INT_LINK_UP ?
-                   POWERON_STATE : POWEROFF_STATE;
-               queue_work(p_slot->wq, &info->work);
+               pciehp_queue_power_work(p_slot, event == INT_LINK_UP ?
+                                       ENABLE_REQ : DISABLE_REQ);
                break;
        case POWERON_STATE:
                if (event == INT_LINK_UP) {
                        ctrl_info(ctrl,
                                  "Link Up event ignored on slot(%s): already powering on\n",
                                  slot_name(p_slot));
-                       kfree(info);
                } else {
                        ctrl_info(ctrl,
                                  "Link Down event queued on slot(%s): currently getting powered on\n",
                                  slot_name(p_slot));
-                       p_slot->state = POWEROFF_STATE;
-                       queue_work(p_slot->wq, &info->work);
+                       pciehp_queue_power_work(p_slot, DISABLE_REQ);
                }
                break;
        case POWEROFF_STATE:
@@ -371,19 +345,16 @@ static void handle_link_event(struct slot *p_slot, u32 event)
                        ctrl_info(ctrl,
                                  "Link Up event queued on slot(%s): currently getting powered off\n",
                                  slot_name(p_slot));
-                       p_slot->state = POWERON_STATE;
-                       queue_work(p_slot->wq, &info->work);
+                       pciehp_queue_power_work(p_slot, ENABLE_REQ);
                } else {
                        ctrl_info(ctrl,
                                  "Link Down event ignored on slot(%s): already powering off\n",
                                  slot_name(p_slot));
-                       kfree(info);
                }
                break;
        default:
                ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n",
                         p_slot->state, slot_name(p_slot));
-               kfree(info);
                break;
        }
 }
index ee0ebff103a412bc3db69c05f0a30ecc1872be48..31f31d460fc9de789d28d72365122224fa3b2551 100644 (file)
@@ -54,24 +54,29 @@ static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn)
  * The PF consumes one bus number.  NumVFs, First VF Offset, and VF Stride
  * determine how many additional bus numbers will be consumed by VFs.
  *
- * Iterate over all valid NumVFs and calculate the maximum number of bus
- * numbers that could ever be required.
+ * Iterate over all valid NumVFs, validate offset and stride, and calculate
+ * the maximum number of bus numbers that could ever be required.
  */
-static inline u8 virtfn_max_buses(struct pci_dev *dev)
+static int compute_max_vf_buses(struct pci_dev *dev)
 {
        struct pci_sriov *iov = dev->sriov;
-       int nr_virtfn;
-       u8 max = 0;
-       int busnr;
+       int nr_virtfn, busnr, rc = 0;
 
-       for (nr_virtfn = 1; nr_virtfn <= iov->total_VFs; nr_virtfn++) {
+       for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) {
                pci_iov_set_numvfs(dev, nr_virtfn);
+               if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) {
+                       rc = -EIO;
+                       goto out;
+               }
+
                busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1);
-               if (busnr > max)
-                       max = busnr;
+               if (busnr > iov->max_VF_buses)
+                       iov->max_VF_buses = busnr;
        }
 
-       return max;
+out:
+       pci_iov_set_numvfs(dev, 0);
+       return rc;
 }
 
 static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
@@ -222,21 +227,25 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
 
 int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
 {
-       return 0;
+       return 0;
+}
+
+int __weak pcibios_sriov_disable(struct pci_dev *pdev)
+{
+       return 0;
 }
 
 static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 {
        int rc;
-       int i, j;
+       int i;
        int nres;
-       u16 offset, stride, initial;
+       u16 initial;
        struct resource *res;
        struct pci_dev *pdev;
        struct pci_sriov *iov = dev->sriov;
        int bars = 0;
        int bus;
-       int retval;
 
        if (!nr_virtfn)
                return 0;
@@ -253,11 +262,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
            (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
                return -EINVAL;
 
-       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
-       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
-       if (!offset || (nr_virtfn > 1 && !stride))
-               return -EIO;
-
        nres = 0;
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                bars |= (1 << (i + PCI_IOV_RESOURCES));
@@ -270,9 +274,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
                return -ENOMEM;
        }
 
-       iov->offset = offset;
-       iov->stride = stride;
-
        bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1);
        if (bus > dev->bus->busn_res.end) {
                dev_err(&dev->dev, "can't enable %d VFs (bus %02x out of range of %pR)\n",
@@ -313,10 +314,10 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        if (nr_virtfn < initial)
                initial = nr_virtfn;
 
-       if ((retval = pcibios_sriov_enable(dev, initial))) {
-               dev_err(&dev->dev, "failure %d from pcibios_sriov_enable()\n",
-                       retval);
-               return retval;
+       rc = pcibios_sriov_enable(dev, initial);
+       if (rc) {
+               dev_err(&dev->dev, "failure %d from pcibios_sriov_enable()\n", rc);
+               goto err_pcibios;
        }
 
        for (i = 0; i < initial; i++) {
@@ -331,27 +332,24 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        return 0;
 
 failed:
-       for (j = 0; j < i; j++)
-               virtfn_remove(dev, j, 0);
+       while (i--)
+               virtfn_remove(dev, i, 0);
 
+       pcibios_sriov_disable(dev);
+err_pcibios:
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-       pci_iov_set_numvfs(dev, 0);
        ssleep(1);
        pci_cfg_access_unlock(dev);
 
        if (iov->link != dev->devfn)
                sysfs_remove_link(&dev->dev.kobj, "dep_link");
 
+       pci_iov_set_numvfs(dev, 0);
        return rc;
 }
 
-int __weak pcibios_sriov_disable(struct pci_dev *pdev)
-{
-       return 0;
-}
-
 static void sriov_disable(struct pci_dev *dev)
 {
        int i;
@@ -384,7 +382,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
        int rc;
        int nres;
        u32 pgsz;
-       u16 ctrl, total, offset, stride;
+       u16 ctrl, total;
        struct pci_sriov *iov;
        struct resource *res;
        struct pci_dev *pdev;
@@ -399,10 +397,6 @@ static int sriov_init(struct pci_dev *dev, int pos)
                ssleep(1);
        }
 
-       pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
-       if (!total)
-               return 0;
-
        ctrl = 0;
        list_for_each_entry(pdev, &dev->bus->devices, bus_list)
                if (pdev->is_physfn)
@@ -414,11 +408,10 @@ static int sriov_init(struct pci_dev *dev, int pos)
 
 found:
        pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
-       pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, 0);
-       pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
-       pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
-       if (!offset || (total > 1 && !stride))
-               return -EIO;
+
+       pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
+       if (!total)
+               return 0;
 
        pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
        i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
@@ -436,8 +429,15 @@ found:
        nres = 0;
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                res = &dev->resource[i + PCI_IOV_RESOURCES];
-               bar64 = __pci_read_base(dev, pci_bar_unknown, res,
-                                       pos + PCI_SRIOV_BAR + i * 4);
+               /*
+                * If it is already FIXED, don't change it, something
+                * (perhaps EA or header fixups) wants it this way.
+                */
+               if (res->flags & IORESOURCE_PCI_FIXED)
+                       bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
+               else
+                       bar64 = __pci_read_base(dev, pci_bar_unknown, res,
+                                               pos + PCI_SRIOV_BAR + i * 4);
                if (!res->flags)
                        continue;
                if (resource_size(res) & (PAGE_SIZE - 1)) {
@@ -456,8 +456,6 @@ found:
        iov->nres = nres;
        iov->ctrl = ctrl;
        iov->total_VFs = total;
-       iov->offset = offset;
-       iov->stride = stride;
        iov->pgsz = pgsz;
        iov->self = dev;
        pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
@@ -474,10 +472,15 @@ found:
 
        dev->sriov = iov;
        dev->is_physfn = 1;
-       iov->max_VF_buses = virtfn_max_buses(dev);
+       rc = compute_max_vf_buses(dev);
+       if (rc)
+               goto fail_max_buses;
 
        return 0;
 
+fail_max_buses:
+       dev->sriov = NULL;
+       dev->is_physfn = 0;
 failed:
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                res = &dev->resource[i + PCI_IOV_RESOURCES];
index 45a51486d080a54fa987eaa230106df5895b3b09..53e463244bb7e35ac368ff088a4976c2153fce3d 100644 (file)
@@ -106,9 +106,12 @@ void __weak arch_teardown_msi_irq(unsigned int irq)
 
 int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
+       struct msi_controller *chip = dev->bus->msi;
        struct msi_desc *entry;
        int ret;
 
+       if (chip && chip->setup_irqs)
+               return chip->setup_irqs(chip, dev, nvec, type);
        /*
         * If an architecture wants to support multiple MSI, it needs to
         * override arch_setup_msi_irqs()
@@ -476,10 +479,11 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
        int ret = -ENOMEM;
        int num_msi = 0;
        int count = 0;
+       int i;
 
        /* Determine how many msi entries we have */
        for_each_pci_msi_entry(entry, pdev)
-               ++num_msi;
+               num_msi += entry->nvec_used;
        if (!num_msi)
                return 0;
 
@@ -488,19 +492,21 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
        if (!msi_attrs)
                return -ENOMEM;
        for_each_pci_msi_entry(entry, pdev) {
-               msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
-               if (!msi_dev_attr)
-                       goto error_attrs;
-               msi_attrs[count] = &msi_dev_attr->attr;
-
-               sysfs_attr_init(&msi_dev_attr->attr);
-               msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d",
-                                                   entry->irq);
-               if (!msi_dev_attr->attr.name)
-                       goto error_attrs;
-               msi_dev_attr->attr.mode = S_IRUGO;
-               msi_dev_attr->show = msi_mode_show;
-               ++count;
+               for (i = 0; i < entry->nvec_used; i++) {
+                       msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
+                       if (!msi_dev_attr)
+                               goto error_attrs;
+                       msi_attrs[count] = &msi_dev_attr->attr;
+
+                       sysfs_attr_init(&msi_dev_attr->attr);
+                       msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d",
+                                                           entry->irq + i);
+                       if (!msi_dev_attr->attr.name)
+                               goto error_attrs;
+                       msi_dev_attr->attr.mode = S_IRUGO;
+                       msi_dev_attr->show = msi_mode_show;
+                       ++count;
+               }
        }
 
        msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL);
index 306124bba61e2a1dbf3e116e33b8768db192bc25..4446fcb5effd347d87fb6314473297acc4558769 100644 (file)
@@ -172,7 +172,7 @@ static ssize_t store_remove_id(struct device_driver *driver, const char *buf,
        __u32 vendor, device, subvendor = PCI_ANY_ID,
                subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
        int fields = 0;
-       int retval = -ENODEV;
+       size_t retval = -ENODEV;
 
        fields = sscanf(buf, "%x %x %x %x %x %x",
                        &vendor, &device, &subvendor, &subdevice,
@@ -190,15 +190,13 @@ static ssize_t store_remove_id(struct device_driver *driver, const char *buf,
                    !((id->class ^ class) & class_mask)) {
                        list_del(&dynid->node);
                        kfree(dynid);
-                       retval = 0;
+                       retval = count;
                        break;
                }
        }
        spin_unlock(&pdrv->dynids.lock);
 
-       if (retval)
-               return retval;
-       return count;
+       return retval;
 }
 static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
index 78693fc5dbe9e680952687d4a0f04d08e7fb0ca6..314db8c1047a30228f68072f820d7f40babc2ad0 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pci_hotplug.h>
 #include <asm-generic/pci-bridge.h>
 #include <asm/setup.h>
+#include <linux/aer.h>
 #include "pci.h"
 
 const char *pci_power_names[] = {
@@ -457,6 +458,30 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
 }
 EXPORT_SYMBOL(pci_find_parent_resource);
 
+/**
+ * pci_find_pcie_root_port - return PCIe Root Port
+ * @dev: PCI device to query
+ *
+ * Traverse up the parent chain and return the PCIe Root Port PCI Device
+ * for a given PCI Device.
+ */
+struct pci_dev *pci_find_pcie_root_port(struct pci_dev *dev)
+{
+       struct pci_dev *bridge, *highest_pcie_bridge = NULL;
+
+       bridge = pci_upstream_bridge(dev);
+       while (bridge && pci_is_pcie(bridge)) {
+               highest_pcie_bridge = bridge;
+               bridge = pci_upstream_bridge(bridge);
+       }
+
+       if (pci_pcie_type(highest_pcie_bridge) != PCI_EXP_TYPE_ROOT_PORT)
+               return NULL;
+
+       return highest_pcie_bridge;
+}
+EXPORT_SYMBOL(pci_find_pcie_root_port);
+
 /**
  * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
  * @dev: the PCI device to operate on
@@ -484,7 +509,7 @@ int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
 }
 
 /**
- * pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
+ * pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
  * @dev: PCI device to have its BARs restored
  *
  * Restore the BAR values for a given device, so as to make it
@@ -494,6 +519,10 @@ static void pci_restore_bars(struct pci_dev *dev)
 {
        int i;
 
+       /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
+       if (dev->is_virtfn)
+               return;
+
        for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
                pci_update_resource(dev, i);
 }
@@ -1099,6 +1128,8 @@ void pci_restore_state(struct pci_dev *dev)
        pci_restore_ats_state(dev);
        pci_restore_vc_state(dev);
 
+       pci_cleanup_aer_error_status_regs(dev);
+
        pci_restore_config_space(dev);
 
        pci_restore_pcix_state(dev);
@@ -2196,6 +2227,198 @@ void pci_pm_init(struct pci_dev *dev)
        }
 }
 
+static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
+{
+       unsigned long flags = IORESOURCE_PCI_FIXED;
+
+       switch (prop) {
+       case PCI_EA_P_MEM:
+       case PCI_EA_P_VF_MEM:
+               flags |= IORESOURCE_MEM;
+               break;
+       case PCI_EA_P_MEM_PREFETCH:
+       case PCI_EA_P_VF_MEM_PREFETCH:
+               flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+               break;
+       case PCI_EA_P_IO:
+               flags |= IORESOURCE_IO;
+               break;
+       default:
+               return 0;
+       }
+
+       return flags;
+}
+
+static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei,
+                                           u8 prop)
+{
+       if (bei <= PCI_EA_BEI_BAR5 && prop <= PCI_EA_P_IO)
+               return &dev->resource[bei];
+#ifdef CONFIG_PCI_IOV
+       else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5 &&
+                (prop == PCI_EA_P_VF_MEM || prop == PCI_EA_P_VF_MEM_PREFETCH))
+               return &dev->resource[PCI_IOV_RESOURCES +
+                                     bei - PCI_EA_BEI_VF_BAR0];
+#endif
+       else if (bei == PCI_EA_BEI_ROM)
+               return &dev->resource[PCI_ROM_RESOURCE];
+       else
+               return NULL;
+}
+
+/* Read an Enhanced Allocation (EA) entry */
+static int pci_ea_read(struct pci_dev *dev, int offset)
+{
+       struct resource *res;
+       int ent_size, ent_offset = offset;
+       resource_size_t start, end;
+       unsigned long flags;
+       u32 dw0, bei, base, max_offset;
+       u8 prop;
+       bool support_64 = (sizeof(resource_size_t) >= 8);
+
+       pci_read_config_dword(dev, ent_offset, &dw0);
+       ent_offset += 4;
+
+       /* Entry size field indicates DWORDs after 1st */
+       ent_size = ((dw0 & PCI_EA_ES) + 1) << 2;
+
+       if (!(dw0 & PCI_EA_ENABLE)) /* Entry not enabled */
+               goto out;
+
+       bei = (dw0 & PCI_EA_BEI) >> 4;
+       prop = (dw0 & PCI_EA_PP) >> 8;
+
+       /*
+        * If the Property is in the reserved range, try the Secondary
+        * Property instead.
+        */
+       if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
+               prop = (dw0 & PCI_EA_SP) >> 16;
+       if (prop > PCI_EA_P_BRIDGE_IO)
+               goto out;
+
+       res = pci_ea_get_resource(dev, bei, prop);
+       if (!res) {
+               dev_err(&dev->dev, "Unsupported EA entry BEI: %u\n", bei);
+               goto out;
+       }
+
+       flags = pci_ea_flags(dev, prop);
+       if (!flags) {
+               dev_err(&dev->dev, "Unsupported EA properties: %#x\n", prop);
+               goto out;
+       }
+
+       /* Read Base */
+       pci_read_config_dword(dev, ent_offset, &base);
+       start = (base & PCI_EA_FIELD_MASK);
+       ent_offset += 4;
+
+       /* Read MaxOffset */
+       pci_read_config_dword(dev, ent_offset, &max_offset);
+       ent_offset += 4;
+
+       /* Read Base MSBs (if 64-bit entry) */
+       if (base & PCI_EA_IS_64) {
+               u32 base_upper;
+
+               pci_read_config_dword(dev, ent_offset, &base_upper);
+               ent_offset += 4;
+
+               flags |= IORESOURCE_MEM_64;
+
+               /* entry starts above 32-bit boundary, can't use */
+               if (!support_64 && base_upper)
+                       goto out;
+
+               if (support_64)
+                       start |= ((u64)base_upper << 32);
+       }
+
+       end = start + (max_offset | 0x03);
+
+       /* Read MaxOffset MSBs (if 64-bit entry) */
+       if (max_offset & PCI_EA_IS_64) {
+               u32 max_offset_upper;
+
+               pci_read_config_dword(dev, ent_offset, &max_offset_upper);
+               ent_offset += 4;
+
+               flags |= IORESOURCE_MEM_64;
+
+               /* entry too big, can't use */
+               if (!support_64 && max_offset_upper)
+                       goto out;
+
+               if (support_64)
+                       end += ((u64)max_offset_upper << 32);
+       }
+
+       if (end < start) {
+               dev_err(&dev->dev, "EA Entry crosses address boundary\n");
+               goto out;
+       }
+
+       if (ent_size != ent_offset - offset) {
+               dev_err(&dev->dev,
+                       "EA Entry Size (%d) does not match length read (%d)\n",
+                       ent_size, ent_offset - offset);
+               goto out;
+       }
+
+       res->name = pci_name(dev);
+       res->start = start;
+       res->end = end;
+       res->flags = flags;
+
+       if (bei <= PCI_EA_BEI_BAR5)
+               dev_printk(KERN_DEBUG, &dev->dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+                          bei, res, prop);
+       else if (bei == PCI_EA_BEI_ROM)
+               dev_printk(KERN_DEBUG, &dev->dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
+                          res, prop);
+       else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
+               dev_printk(KERN_DEBUG, &dev->dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+                          bei - PCI_EA_BEI_VF_BAR0, res, prop);
+       else
+               dev_printk(KERN_DEBUG, &dev->dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
+                          bei, res, prop);
+
+out:
+       return offset + ent_size;
+}
+
+/* Enhanced Allocation Initalization */
+void pci_ea_init(struct pci_dev *dev)
+{
+       int ea;
+       u8 num_ent;
+       int offset;
+       int i;
+
+       /* find PCI EA capability in list */
+       ea = pci_find_capability(dev, PCI_CAP_ID_EA);
+       if (!ea)
+               return;
+
+       /* determine the number of entries */
+       pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT,
+                                       &num_ent);
+       num_ent &= PCI_EA_NUM_ENT_MASK;
+
+       offset = ea + PCI_EA_FIRST_ENT;
+
+       /* Skip DWORD 2 for type 1 functions */
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+               offset += 4;
+
+       /* parse each EA entry */
+       for (i = 0; i < num_ent; ++i)
+               offset = pci_ea_read(dev, offset);
+}
+
 static void pci_add_saved_cap(struct pci_dev *pci_dev,
        struct pci_cap_saved_state *new_cap)
 {
index 037e787a3ad582c62121175a6b17339ed546d83b..fd2f03fa53f33a34977fc8713fd8cf6759cad2d5 100644 (file)
@@ -79,6 +79,7 @@ void pci_dev_complete_resume(struct pci_dev *pci_dev);
 void pci_config_pm_runtime_get(struct pci_dev *dev);
 void pci_config_pm_runtime_put(struct pci_dev *dev);
 void pci_pm_init(struct pci_dev *dev);
+void pci_ea_init(struct pci_dev *dev);
 void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
 
index 9803e3d039febf7f5ea0e3613da5bb07243d501e..fba785e9df75570b35a9b90e671bc8d5dbad6e91 100644 (file)
@@ -74,6 +74,34 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
 
+int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
+{
+       int pos;
+       u32 status;
+       int port_type;
+
+       if (!pci_is_pcie(dev))
+               return -ENODEV;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!pos)
+               return -EIO;
+
+       port_type = pci_pcie_type(dev);
+       if (port_type == PCI_EXP_TYPE_ROOT_PORT) {
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
+       }
+
+       pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
+       pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status);
+
+       pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+       pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+
+       return 0;
+}
+
 /**
  * add_error_device - list device to be handled
  * @e_info: pointer to error info
index f14a970b61fa59bf00b6e97474da3ec024ba315e..f53b8e85f137902f6e8b0667ae9f0539c06537a1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/aer.h>
 #include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
@@ -1597,6 +1598,9 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
 
 static void pci_init_capabilities(struct pci_dev *dev)
 {
+       /* Enhanced Allocation */
+       pci_ea_init(dev);
+
        /* MSI/MSI-X list */
        pci_msi_init_pci_dev(dev);
 
@@ -1620,6 +1624,8 @@ static void pci_init_capabilities(struct pci_dev *dev)
 
        /* Enable ACS P2P upstream forwarding */
        pci_enable_acs(dev);
+
+       pci_cleanup_aer_error_status_regs(dev);
 }
 
 /*
index b03373fd05ca3854f9816d47db5a2868a6509420..7e327309cf69f612b05cdb1544ff5c4deba9f68e 100644 (file)
@@ -2246,6 +2246,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disab
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
 static void quirk_disable_msi(struct pci_dev *dev)
@@ -3707,6 +3708,63 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6868, PCI_CLASS_NOT_DEFINED, 8,
 DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, PCI_CLASS_NOT_DEFINED, 8,
                              quirk_tw686x_class);
 
+/*
+ * Per PCIe r3.0, sec 2.2.9, "Completion headers must supply the same
+ * values for the Attribute as were supplied in the header of the
+ * corresponding Request, except as explicitly allowed when IDO is used."
+ *
+ * If a non-compliant device generates a completion with a different
+ * attribute than the request, the receiver may accept it (which itself
+ * seems non-compliant based on sec 2.3.2), or it may handle it as a
+ * Malformed TLP or an Unexpected Completion, which will probably lead to a
+ * device access timeout.
+ *
+ * If the non-compliant device generates completions with zero attributes
+ * (instead of copying the attributes from the request), we can work around
+ * this by disabling the "Relaxed Ordering" and "No Snoop" attributes in
+ * upstream devices so they always generate requests with zero attributes.
+ *
+ * This affects other devices under the same Root Port, but since these
+ * attributes are performance hints, there should be no functional problem.
+ *
+ * Note that Configuration Space accesses are never supposed to have TLP
+ * Attributes, so we're safe waiting till after any Configuration Space
+ * accesses to do the Root Port fixup.
+ */
+static void quirk_disable_root_port_attributes(struct pci_dev *pdev)
+{
+       struct pci_dev *root_port = pci_find_pcie_root_port(pdev);
+
+       if (!root_port) {
+               dev_warn(&pdev->dev, "PCIe Completion erratum may cause device errors\n");
+               return;
+       }
+
+       dev_info(&root_port->dev, "Disabling No Snoop/Relaxed Ordering Attributes to avoid PCIe Completion erratum in %s\n",
+                dev_name(&pdev->dev));
+       pcie_capability_clear_and_set_word(root_port, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_RELAX_EN |
+                                          PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
+}
+
+/*
+ * The Chelsio T5 chip fails to copy TLP Attributes from a Request to the
+ * Completion it generates.
+ */
+static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
+{
+       /*
+        * This mask/compare operation selects for Physical Function 4 on a
+        * T5.  We only need to fix up the Root Port once for any of the
+        * PFs.  PF[0..3] have PCI Device IDs of 0x50xx, but PF4 is uniquely
+        * 0x54xx so we use that one,
+        */
+       if ((pdev->device & 0xff00) == 0x5400)
+               quirk_disable_root_port_attributes(pdev);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+                        quirk_chelsio_T5_disable_root_port_attributes);
+
 /*
  * AMD has indicated that the devices below do not support peer-to-peer
  * in any system where they are found in the southbridge with an AMD
index 508cc56130e3f88d1b01716a7a00fead250fdf1c..1723ac1b30e10f2ff4213f8a65ceeb0a3ff7a786 100644 (file)
@@ -1037,9 +1037,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                        struct resource *r = &dev->resource[i];
                        resource_size_t r_size;
 
-                       if (r->parent || ((r->flags & mask) != type &&
-                                         (r->flags & mask) != type2 &&
-                                         (r->flags & mask) != type3))
+                       if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) ||
+                           ((r->flags & mask) != type &&
+                            (r->flags & mask) != type2 &&
+                            (r->flags & mask) != type3))
                                continue;
                        r_size = resource_size(r);
 #ifdef CONFIG_PCI_IOV
@@ -1340,6 +1341,47 @@ void pci_bus_size_bridges(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
+static void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r)
+{
+       int i;
+       struct resource *parent_r;
+       unsigned long mask = IORESOURCE_IO | IORESOURCE_MEM |
+                            IORESOURCE_PREFETCH;
+
+       pci_bus_for_each_resource(b, parent_r, i) {
+               if (!parent_r)
+                       continue;
+
+               if ((r->flags & mask) == (parent_r->flags & mask) &&
+                   resource_contains(parent_r, r))
+                       request_resource(parent_r, r);
+       }
+}
+
+/*
+ * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they
+ * are skipped by pbus_assign_resources_sorted().
+ */
+static void pdev_assign_fixed_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = 0; i <  PCI_NUM_RESOURCES; i++) {
+               struct pci_bus *b;
+               struct resource *r = &dev->resource[i];
+
+               if (r->parent || !(r->flags & IORESOURCE_PCI_FIXED) ||
+                   !(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+                       continue;
+
+               b = dev->bus;
+               while (b && !r->parent) {
+                       assign_fixed_resource_on_bus(b, r);
+                       b = b->parent;
+               }
+       }
+}
+
 void __pci_bus_assign_resources(const struct pci_bus *bus,
                                struct list_head *realloc_head,
                                struct list_head *fail_head)
@@ -1350,6 +1392,8 @@ void __pci_bus_assign_resources(const struct pci_bus *bus,
        pbus_assign_resources_sorted(bus, realloc_head, fail_head);
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
+               pdev_assign_fixed_resources(dev);
+
                b = dev->subordinate;
                if (!b)
                        continue;
index 232f9254c11acf5b45d9b20f9fc4169dfad79084..604011e047d60b9db26e40e54769aeb7a957f53e 100644 (file)
@@ -36,6 +36,11 @@ void pci_update_resource(struct pci_dev *dev, int resno)
        enum pci_bar_type type;
        struct resource *res = dev->resource + resno;
 
+       if (dev->is_virtfn) {
+               dev_warn(&dev->dev, "can't update VF BAR%d\n", resno);
+               return;
+       }
+
        /*
         * Ignore resources for unimplemented BARs and unused resource slots
         * for 64 bit BARs.
@@ -177,6 +182,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
        end = res->end;
        res->start = fw_addr;
        res->end = res->start + size - 1;
+       res->flags &= ~IORESOURCE_UNSET;
 
        root = pci_find_parent_resource(dev, res);
        if (!root) {
@@ -194,6 +200,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
                         resno, res, conflict->name, conflict);
                res->start = start;
                res->end = end;
+               res->flags |= IORESOURCE_UNSET;
                return -EBUSY;
        }
        return 0;
index 97c2be195efc36eeb76bd848f2c1327be7f168c2..c62e5e11ca4ba013244cf74d9d38b014fc8740ba 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/mutex.h>
 #include <asm/bios_ebda.h>
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 static bool force;
 module_param(force, bool, 0);
index e2065e06a3f308ab7050d714edea381572debc71..55663b3d72823b9a20eeca4c6fee94d227248aed 100644 (file)
@@ -78,7 +78,7 @@
 #include <asm/processor.h>
 #include "intel_ips.h"
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
 
index 95f7a76cfafcf8a296f43edec9d22ba7ce342c59..d2f480b04a52ed4f882fe3ca9b0b79113ef804a4 100644 (file)
@@ -242,13 +242,6 @@ config SCSI_SCAN_ASYNC
          system continues booting, and even probe devices on different
          busses in parallel, leading to a significant speed-up.
 
-         If you have built SCSI as modules, enabling this option can
-         be a problem as the devices may not have been found by the
-         time your system expects them to have been.  You can load the
-         scsi_wait_scan module to ensure that all scans have completed.
-         If you build your SCSI drivers into the kernel, then everything
-         will work fine if you say Y here.
-
          You can override this choice by specifying "scsi_mod.scan=sync"
          or async on the kernel's command line.
 
index 7c3365864242c9aa7367a030c465f3b4cf5925f9..ae87d6c19f17034448037732c39c633b1a645096 100644 (file)
@@ -12,7 +12,7 @@
 #include "ql4_glbl.h"
 #include "ql4_inline.h"
 
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 #define TIMEOUT_100_MS 100
 #define MASK(n)                DMA_BIT_MASK(n)
index 5f78b42b427aef46d8567789ce1cb36bf3fae00e..263db37de7c807821ffe98b2156252b4ecf24ebf 100644 (file)
@@ -123,7 +123,9 @@ extern kib_tunables_t  kiblnd_tunables;
                                     IBLND_CREDIT_HIGHWATER_V1 : \
                                     *kiblnd_tunables.kib_peercredits_hiw) /* when eagerly to return credits */
 
-#define kiblnd_rdma_create_id(cb, dev, ps, qpt) rdma_create_id(cb, dev, ps, qpt)
+#define kiblnd_rdma_create_id(cb, dev, ps, qpt) rdma_create_id(&init_net, \
+                                                              cb, dev, \
+                                                              ps, qpt)
 
 static inline int
 kiblnd_concurrent_sends_v1(void)
@@ -504,7 +506,7 @@ typedef struct kib_tx                         /* transmit message */
        __u64                 tx_msgaddr;     /* message buffer (I/O addr) */
        DECLARE_PCI_UNMAP_ADDR(tx_msgunmap);  /* for dma_unmap_single() */
        int                   tx_nwrq;        /* # send work items */
-       struct ib_send_wr     *tx_wrq;        /* send work items... */
+       struct ib_rdma_wr     *tx_wrq;        /* send work items... */
        struct ib_sge         *tx_sge;        /* ...and their memory */
        kib_rdma_desc_t       *tx_rd;         /* rdma descriptor */
        int                   tx_nfrags;      /* # entries in... */
index 8989e36091fba7f70b3ddd55c78a2ca49f01cc3d..260750354a41707311aaec9afde6667e34959e5a 100644 (file)
@@ -838,7 +838,7 @@ kiblnd_post_tx_locked(kib_conn_t *conn, kib_tx_t *tx, int credit)
                /* close_conn will launch failover */
                rc = -ENETDOWN;
        } else {
-               rc = ib_post_send(conn->ibc_cmid->qp, tx->tx_wrq, &bad_wrq);
+               rc = ib_post_send(conn->ibc_cmid->qp, &tx->tx_wrq->wr, &bad_wrq);
        }
 
        conn->ibc_last_send = jiffies;
@@ -1012,7 +1012,7 @@ kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob)
 {
        kib_hca_dev_t *hdev = tx->tx_pool->tpo_hdev;
        struct ib_sge *sge = &tx->tx_sge[tx->tx_nwrq];
-       struct ib_send_wr *wrq = &tx->tx_wrq[tx->tx_nwrq];
+       struct ib_rdma_wr *wrq = &tx->tx_wrq[tx->tx_nwrq];
        int nob = offsetof(kib_msg_t, ibm_u) + body_nob;
        struct ib_mr *mr;
 
@@ -1031,12 +1031,12 @@ kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob)
 
        memset(wrq, 0, sizeof(*wrq));
 
-       wrq->next       = NULL;
-       wrq->wr_id      = kiblnd_ptr2wreqid(tx, IBLND_WID_TX);
-       wrq->sg_list    = sge;
-       wrq->num_sge    = 1;
-       wrq->opcode     = IB_WR_SEND;
-       wrq->send_flags = IB_SEND_SIGNALED;
+       wrq->wr.next       = NULL;
+       wrq->wr.wr_id      = kiblnd_ptr2wreqid(tx, IBLND_WID_TX);
+       wrq->wr.sg_list    = sge;
+       wrq->wr.num_sge    = 1;
+       wrq->wr.opcode     = IB_WR_SEND;
+       wrq->wr.send_flags = IB_SEND_SIGNALED;
 
        tx->tx_nwrq++;
 }
@@ -1048,7 +1048,7 @@ kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type,
        kib_msg_t *ibmsg = tx->tx_msg;
        kib_rdma_desc_t *srcrd = tx->tx_rd;
        struct ib_sge *sge = &tx->tx_sge[0];
-       struct ib_send_wr *wrq = &tx->tx_wrq[0];
+       struct ib_rdma_wr *wrq = &tx->tx_wrq[0], *next;
        int rc  = resid;
        int srcidx;
        int dstidx;
@@ -1094,16 +1094,17 @@ kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type,
                sge->length = wrknob;
 
                wrq = &tx->tx_wrq[tx->tx_nwrq];
+               next = wrq + 1;
 
-               wrq->next       = wrq + 1;
-               wrq->wr_id      = kiblnd_ptr2wreqid(tx, IBLND_WID_RDMA);
-               wrq->sg_list    = sge;
-               wrq->num_sge    = 1;
-               wrq->opcode     = IB_WR_RDMA_WRITE;
-               wrq->send_flags = 0;
+               wrq->wr.next       = &next->wr;
+               wrq->wr.wr_id      = kiblnd_ptr2wreqid(tx, IBLND_WID_RDMA);
+               wrq->wr.sg_list    = sge;
+               wrq->wr.num_sge    = 1;
+               wrq->wr.opcode     = IB_WR_RDMA_WRITE;
+               wrq->wr.send_flags = 0;
 
-               wrq->wr.rdma.remote_addr = kiblnd_rd_frag_addr(dstrd, dstidx);
-               wrq->wr.rdma.rkey        = kiblnd_rd_frag_key(dstrd, dstidx);
+               wrq->remote_addr = kiblnd_rd_frag_addr(dstrd, dstidx);
+               wrq->rkey        = kiblnd_rd_frag_key(dstrd, dstidx);
 
                srcidx = kiblnd_rd_consume_frag(srcrd, srcidx, wrknob);
                dstidx = kiblnd_rd_consume_frag(dstrd, dstidx, wrknob);
index 9dba16f1fac4c0266c08a3eb233348827b0faad6..47bb56f1f8c0d65c93aa5c50435f982603ed1a05 100644 (file)
@@ -613,7 +613,8 @@ static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
 #ifdef CONFIG_MTD_SPINAND_ONDIEECC
 static int spinand_write_page_hwecc(struct mtd_info *mtd,
                                    struct nand_chip *chip,
-                                   const u8 *buf, int oob_required)
+                                   const u8 *buf, int oob_required,
+                                   int page)
 {
        const u8 *p = buf;
        int eccsize = chip->ecc.size;
@@ -909,8 +910,7 @@ static int spinand_probe(struct spi_device *spi_nand)
        dev_set_drvdata(&spi_nand->dev, mtd);
 
        mtd->priv = chip;
-       mtd->name = dev_name(&spi_nand->dev);
-       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &spi_nand->dev;
        mtd->oobsize = 64;
 
        if (nand_scan(mtd, 1))
index e0a7aff0eb2a5a266867287a5a22414971d404c0..ca364dbe369c1c579508849c0551ce9fc38fdac6 100644 (file)
@@ -860,9 +860,9 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                                flags |= SQ_READ_FENCE;
                        }
                        wr.sqwr.rdma_write.remote_stag =
-                           cpu_to_be32(ib_wr->wr.rdma.rkey);
+                           cpu_to_be32(rdma_wr(ib_wr)->rkey);
                        wr.sqwr.rdma_write.remote_to =
-                           cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+                           cpu_to_be64(rdma_wr(ib_wr)->remote_addr);
                        err = move_sgl((struct c2_data_addr *)
                                       & (wr.sqwr.rdma_write.data),
                                       ib_wr->sg_list,
@@ -889,9 +889,9 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                        wr.sqwr.rdma_read.local_to =
                            cpu_to_be64(ib_wr->sg_list->addr);
                        wr.sqwr.rdma_read.remote_stag =
-                           cpu_to_be32(ib_wr->wr.rdma.rkey);
+                           cpu_to_be32(rdma_wr(ib_wr)->rkey);
                        wr.sqwr.rdma_read.remote_to =
-                           cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+                           cpu_to_be64(rdma_wr(ib_wr)->remote_addr);
                        wr.sqwr.rdma_read.length =
                            cpu_to_be32(ib_wr->sg_list->length);
                        break;
index 47f94984353de9afac694d51806696d5c6d3d7c8..10e2074384f5d83019b222e711b96459441bf378 100644 (file)
@@ -110,19 +110,19 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
 /* need ib_mad struct */
 #include <rdma/ib_mad.h>
 
-static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
+static void trace_ud_wr(const struct ib_ud_wr *ud_wr)
 {
        int idx;
        int j;
-       while (send_wr) {
-               struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
-               struct ib_sge *sge = send_wr->sg_list;
-               ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
-                            "send_flags=%x opcode=%x", idx, send_wr->wr_id,
-                            send_wr->num_sge, send_wr->send_flags,
-                            send_wr->opcode);
+       while (ud_wr) {
+               struct ib_mad_hdr *mad_hdr = ud_wrmad_hdr;
+               struct ib_sge *sge = ud_wr->wr.sg_list;
+               ehca_gen_dbg("ud_wr#%x wr_id=%lx num_sge=%x "
+                            "send_flags=%x opcode=%x", idx, ud_wr->wr.wr_id,
+                            ud_wr->wr.num_sge, ud_wr->wr.send_flags,
+                            ud_wr->.wr.opcode);
                if (mad_hdr) {
-                       ehca_gen_dbg("send_wr#%x mad_hdr base_version=%x "
+                       ehca_gen_dbg("ud_wr#%x mad_hdr base_version=%x "
                                     "mgmt_class=%x class_version=%x method=%x "
                                     "status=%x class_specific=%x tid=%lx "
                                     "attr_id=%x resv=%x attr_mod=%x",
@@ -134,33 +134,33 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
                                     mad_hdr->resv,
                                     mad_hdr->attr_mod);
                }
-               for (j = 0; j < send_wr->num_sge; j++) {
+               for (j = 0; j < ud_wr->wr.num_sge; j++) {
                        u8 *data = __va(sge->addr);
-                       ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
+                       ehca_gen_dbg("ud_wr#%x sge#%x addr=%p length=%x "
                                     "lkey=%x",
                                     idx, j, data, sge->length, sge->lkey);
                        /* assume length is n*16 */
-                       ehca_dmp(data, sge->length, "send_wr#%x sge#%x",
+                       ehca_dmp(data, sge->length, "ud_wr#%x sge#%x",
                                 idx, j);
                        sge++;
                } /* eof for j */
                idx++;
-               send_wr = send_wr->next;
-       } /* eof while send_wr */
+               ud_wr = ud_wr(ud_wr->wr.next);
+       } /* eof while ud_wr */
 }
 
 #endif /* DEBUG_GSI_SEND_WR */
 
 static inline int ehca_write_swqe(struct ehca_qp *qp,
                                  struct ehca_wqe *wqe_p,
-                                 const struct ib_send_wr *send_wr,
+                                 struct ib_send_wr *send_wr,
                                  u32 sq_map_idx,
                                  int hidden)
 {
        u32 idx;
        u64 dma_length;
        struct ehca_av *my_av;
-       u32 remote_qkey = send_wr->wr.ud.remote_qkey;
+       u32 remote_qkey;
        struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx];
 
        if (unlikely((send_wr->num_sge < 0) ||
@@ -223,20 +223,21 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
                /* no break is intential here */
        case IB_QPT_UD:
                /* IB 1.2 spec C10-15 compliance */
-               if (send_wr->wr.ud.remote_qkey & 0x80000000)
+               remote_qkey = ud_wr(send_wr)->remote_qkey;
+               if (remote_qkey & 0x80000000)
                        remote_qkey = qp->qkey;
 
-               wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
+               wqe_p->destination_qp_number = ud_wr(send_wr)->remote_qpn << 8;
                wqe_p->local_ee_context_qkey = remote_qkey;
-               if (unlikely(!send_wr->wr.ud.ah)) {
-                       ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
+               if (unlikely(!ud_wr(send_wr)->ah)) {
+                       ehca_gen_err("ud_wr(send_wr) is NULL. qp=%p", qp);
                        return -EINVAL;
                }
-               if (unlikely(send_wr->wr.ud.remote_qpn == 0)) {
+               if (unlikely(ud_wr(send_wr)->remote_qpn == 0)) {
                        ehca_gen_err("dest QP# is 0. qp=%x", qp->real_qp_num);
                        return -EINVAL;
                }
-               my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
+               my_av = container_of(ud_wr(send_wr)->ah, struct ehca_av, ib_ah);
                wqe_p->u.ud_av.ud_av = my_av->av;
 
                /*
@@ -255,9 +256,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
                    qp->qp_type == IB_QPT_GSI)
                        wqe_p->u.ud_av.ud_av.pmtu = 1;
                if (qp->qp_type == IB_QPT_GSI) {
-                       wqe_p->pkeyi = send_wr->wr.ud.pkey_index;
+                       wqe_p->pkeyi = ud_wr(send_wr)->pkey_index;
 #ifdef DEBUG_GSI_SEND_WR
-                       trace_send_wr_ud(send_wr);
+                       trace_ud_wr(ud_wr(send_wr));
 #endif /* DEBUG_GSI_SEND_WR */
                }
                break;
@@ -269,8 +270,8 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
        case IB_QPT_RC:
                /* TODO: atomic not implemented */
                wqe_p->u.nud.remote_virtual_address =
-                       send_wr->wr.rdma.remote_addr;
-               wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey;
+                       rdma_wr(send_wr)->remote_addr;
+               wqe_p->u.nud.rkey = rdma_wr(send_wr)->rkey;
 
                /*
                 * omitted checking of IB_SEND_INLINE
index f6eff177ace1e02f4f5947462785796829937ccd..cb4e6087dfdb263669292140d65da108d825b86e 100644 (file)
@@ -354,58 +354,3 @@ bail:
        rcu_read_unlock();
        return 0;
 }
-
-/*
- * Initialize the memory region specified by the work request.
- */
-int hfi1_fast_reg_mr(struct hfi1_qp *qp, struct ib_send_wr *wr)
-{
-       struct hfi1_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
-       struct hfi1_pd *pd = to_ipd(qp->ibqp.pd);
-       struct hfi1_mregion *mr;
-       u32 rkey = wr->wr.fast_reg.rkey;
-       unsigned i, n, m;
-       int ret = -EINVAL;
-       unsigned long flags;
-       u64 *page_list;
-       size_t ps;
-
-       spin_lock_irqsave(&rkt->lock, flags);
-       if (pd->user || rkey == 0)
-               goto bail;
-
-       mr = rcu_dereference_protected(
-               rkt->table[(rkey >> (32 - hfi1_lkey_table_size))],
-               lockdep_is_held(&rkt->lock));
-       if (unlikely(mr == NULL || qp->ibqp.pd != mr->pd))
-               goto bail;
-
-       if (wr->wr.fast_reg.page_list_len > mr->max_segs)
-               goto bail;
-
-       ps = 1UL << wr->wr.fast_reg.page_shift;
-       if (wr->wr.fast_reg.length > ps * wr->wr.fast_reg.page_list_len)
-               goto bail;
-
-       mr->user_base = wr->wr.fast_reg.iova_start;
-       mr->iova = wr->wr.fast_reg.iova_start;
-       mr->lkey = rkey;
-       mr->length = wr->wr.fast_reg.length;
-       mr->access_flags = wr->wr.fast_reg.access_flags;
-       page_list = wr->wr.fast_reg.page_list->page_list;
-       m = 0;
-       n = 0;
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-               mr->map[m]->segs[n].vaddr = (void *) page_list[i];
-               mr->map[m]->segs[n].length = ps;
-               if (++n == HFI1_SEGSZ) {
-                       m++;
-                       n = 0;
-               }
-       }
-
-       ret = 0;
-bail:
-       spin_unlock_irqrestore(&rkt->lock, flags);
-       return ret;
-}
index 0208fc200c1abadbd96f51a11bac2be26df6e5f3..568f185a022dffa5bf24a1af010261a4b4f7b5c0 100644 (file)
@@ -344,9 +344,10 @@ out:
 
 /*
  * Allocate a memory region usable with the
- * IB_WR_FAST_REG_MR send work request.
+ * IB_WR_REG_MR send work request.
  *
  * Return the memory region on success, otherwise return an errno.
+ * FIXME: IB_WR_REG_MR is not supported
  */
 struct ib_mr *hfi1_alloc_mr(struct ib_pd *pd,
                            enum ib_mr_type mr_type,
@@ -364,36 +365,6 @@ struct ib_mr *hfi1_alloc_mr(struct ib_pd *pd,
        return &mr->ibmr;
 }
 
-struct ib_fast_reg_page_list *
-hfi1_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len)
-{
-       unsigned size = page_list_len * sizeof(u64);
-       struct ib_fast_reg_page_list *pl;
-
-       if (size > PAGE_SIZE)
-               return ERR_PTR(-EINVAL);
-
-       pl = kzalloc(sizeof(*pl), GFP_KERNEL);
-       if (!pl)
-               return ERR_PTR(-ENOMEM);
-
-       pl->page_list = kzalloc(size, GFP_KERNEL);
-       if (!pl->page_list)
-               goto err_free;
-
-       return pl;
-
-err_free:
-       kfree(pl);
-       return ERR_PTR(-ENOMEM);
-}
-
-void hfi1_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl)
-{
-       kfree(pl->page_list);
-       kfree(pl);
-}
-
 /**
  * hfi1_alloc_fmr - allocate a fast memory region
  * @pd: the protection domain for this memory region
index df1fa56eaf851bdfd1bb6feaa160ab196a0ceb6f..f8c36166962f304f451808daf902fbfd765df0cb 100644 (file)
@@ -422,7 +422,7 @@ static void clear_mr_refs(struct hfi1_qp *qp, int clr_sends)
                        if (qp->ibqp.qp_type == IB_QPT_UD ||
                            qp->ibqp.qp_type == IB_QPT_SMI ||
                            qp->ibqp.qp_type == IB_QPT_GSI)
-                               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+                               atomic_dec(&to_iah(wqe->ud_wr.ah)->refcount);
                        if (++qp->s_last >= qp->s_size)
                                qp->s_last = 0;
                }
index 0b19206ff33efd2d594fbd9b7b691688cc798591..5fc93bb312f1b900ead7e1b6ae4f7ed643799f75 100644 (file)
@@ -404,9 +404,9 @@ int hfi1_make_rc_req(struct hfi1_qp *qp)
                                goto bail;
                        }
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / sizeof(u32);
                        wqe->lpsn = wqe->psn;
@@ -455,9 +455,9 @@ int hfi1_make_rc_req(struct hfi1_qp *qp)
                                wqe->lpsn = qp->s_next_psn++;
                        }
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        qp->s_state = OP(RDMA_READ_REQUEST);
                        hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
@@ -488,21 +488,21 @@ int hfi1_make_rc_req(struct hfi1_qp *qp)
                        if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
                                qp->s_state = OP(COMPARE_SWAP);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.swap);
+                                       wqe->atomic_wr.swap);
                                ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                        } else {
                                qp->s_state = OP(FETCH_ADD);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                                ohdr->u.atomic_eth.compare_data = 0;
                        }
                        ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr >> 32);
+                               wqe->atomic_wr.remote_addr >> 32);
                        ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr);
+                               wqe->atomic_wr.remote_addr);
                        ohdr->u.atomic_eth.rkey = cpu_to_be32(
-                               wqe->wr.wr.atomic.rkey);
+                               wqe->atomic_wr.rkey);
                        hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
                        ss = NULL;
                        len = 0;
@@ -629,9 +629,9 @@ int hfi1_make_rc_req(struct hfi1_qp *qp)
                 */
                len = (delta_psn(qp->s_psn, wqe->psn)) * pmtu;
                ohdr->u.rc.reth.vaddr =
-                       cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len);
+                       cpu_to_be64(wqe->rdma_wr.remote_addr + len);
                ohdr->u.rc.reth.rkey =
-                       cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       cpu_to_be32(wqe->rdma_wr.rkey);
                ohdr->u.rc.reth.length = cpu_to_be32(wqe->length - len);
                qp->s_state = OP(RDMA_READ_REQUEST);
                hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
index 8614b070545c90d5fc0e56e575ea0f5d1403aa4a..49bc9fd7a51aee2c3e0e57717ff2514a02c2e327 100644 (file)
@@ -481,8 +481,8 @@ again:
                if (wqe->length == 0)
                        break;
                if (unlikely(!hfi1_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
-                                          wqe->wr.wr.rdma.remote_addr,
-                                          wqe->wr.wr.rdma.rkey,
+                                          wqe->rdma_wr.remote_addr,
+                                          wqe->rdma_wr.rkey,
                                           IB_ACCESS_REMOTE_WRITE)))
                        goto acc_err;
                qp->r_sge.sg_list = NULL;
@@ -494,8 +494,8 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
                        goto inv_err;
                if (unlikely(!hfi1_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
-                                          wqe->wr.wr.rdma.remote_addr,
-                                          wqe->wr.wr.rdma.rkey,
+                                          wqe->rdma_wr.remote_addr,
+                                          wqe->rdma_wr.rkey,
                                           IB_ACCESS_REMOTE_READ)))
                        goto acc_err;
                release = 0;
@@ -512,18 +512,18 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
                if (unlikely(!hfi1_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
-                                          wqe->wr.wr.atomic.remote_addr,
-                                          wqe->wr.wr.atomic.rkey,
+                                          wqe->atomic_wr.remote_addr,
+                                          wqe->atomic_wr.rkey,
                                           IB_ACCESS_REMOTE_ATOMIC)))
                        goto acc_err;
                /* Perform atomic OP and save result. */
                maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
-               sdata = wqe->wr.wr.atomic.compare_add;
+               sdata = wqe->atomic_wr.compare_add;
                *(u64 *) sqp->s_sge.sge.vaddr =
                        (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
                        (u64) atomic64_add_return(sdata, maddr) - sdata :
                        (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
-                                     sdata, wqe->wr.wr.atomic.swap);
+                                     sdata, wqe->atomic_wr.swap);
                hfi1_put_mr(qp->r_sge.sge.mr);
                qp->r_sge.num_sge = 0;
                goto send_comp;
@@ -912,7 +912,7 @@ void hfi1_send_complete(struct hfi1_qp *qp, struct hfi1_swqe *wqe,
        if (qp->ibqp.qp_type == IB_QPT_UD ||
            qp->ibqp.qp_type == IB_QPT_SMI ||
            qp->ibqp.qp_type == IB_QPT_GSI)
-               atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount);
+               atomic_dec(&to_iah(wqe->ud_wr.ah)->refcount);
 
        /* See ch. 11.2.4.1 and 10.7.3.1 */
        if (!(qp->s_flags & HFI1_S_SIGNAL_REQ_WR) ||
index b536f397737c74bc1007d0fe22d83a86b1bda76b..6095039c4485a642736c694590e3d6320086378b 100644 (file)
@@ -147,9 +147,9 @@ int hfi1_make_uc_req(struct hfi1_qp *qp)
                case IB_WR_RDMA_WRITE:
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / 4;
                        if (len > pmtu) {
index d40d1a1e10aa919be1270b795c2ffa406b8a2b39..5a9c784bec04c5ecbcc64fd8fbbde11b70520d8b 100644 (file)
@@ -80,7 +80,7 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
 
        rcu_read_lock();
 
-       qp = hfi1_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn);
+       qp = hfi1_lookup_qpn(ibp, swqe->ud_wr.remote_qpn);
        if (!qp) {
                ibp->n_pkt_drops++;
                rcu_read_unlock();
@@ -98,7 +98,7 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
                goto drop;
        }
 
-       ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(swqe->ud_wr.ah)->attr;
        ppd = ppd_from_ibp(ibp);
 
        if (qp->ibqp.qp_num > 1) {
@@ -128,8 +128,8 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
        if (qp->ibqp.qp_num) {
                u32 qkey;
 
-               qkey = (int)swqe->wr.wr.ud.remote_qkey < 0 ?
-                       sqp->qkey : swqe->wr.wr.ud.remote_qkey;
+               qkey = (int)swqe->ud_wr.remote_qkey < 0 ?
+                       sqp->qkey : swqe->ud_wr.remote_qkey;
                if (unlikely(qkey != qp->qkey)) {
                        u16 lid;
 
@@ -234,7 +234,7 @@ static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe)
        if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI) {
                if (sqp->ibqp.qp_type == IB_QPT_GSI ||
                    sqp->ibqp.qp_type == IB_QPT_SMI)
-                       wc.pkey_index = swqe->wr.wr.ud.pkey_index;
+                       wc.pkey_index = swqe->ud_wr.pkey_index;
                else
                        wc.pkey_index = sqp->s_pkey_index;
        } else {
@@ -309,7 +309,7 @@ int hfi1_make_ud_req(struct hfi1_qp *qp)
        /* Construct the header. */
        ibp = to_iport(qp->ibqp.device, qp->port_num);
        ppd = ppd_from_ibp(ibp);
-       ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(wqe->ud_wr.ah)->attr;
        if (ah_attr->dlid < HFI1_MULTICAST_LID_BASE ||
            ah_attr->dlid == HFI1_PERMISSIVE_LID) {
                lid = ah_attr->dlid & ~((1 << ppd->lmc) - 1);
@@ -401,18 +401,18 @@ int hfi1_make_ud_req(struct hfi1_qp *qp)
                bth0 |= IB_BTH_SOLICITED;
        bth0 |= extra_bytes << 20;
        if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI)
-               bth0 |= hfi1_get_pkey(ibp, wqe->wr.wr.ud.pkey_index);
+               bth0 |= hfi1_get_pkey(ibp, wqe->ud_wr.pkey_index);
        else
                bth0 |= hfi1_get_pkey(ibp, qp->s_pkey_index);
        ohdr->bth[0] = cpu_to_be32(bth0);
-       ohdr->bth[1] = cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
+       ohdr->bth[1] = cpu_to_be32(wqe->ud_wr.remote_qpn);
        ohdr->bth[2] = cpu_to_be32(mask_psn(qp->s_next_psn++));
        /*
         * Qkeys with the high order bit set mean use the
         * qkey from the QP context instead of the WR (see 10.2.5).
         */
-       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
-                                        qp->qkey : wqe->wr.wr.ud.remote_qkey);
+       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
+                                        qp->qkey : wqe->ud_wr.remote_qkey);
        ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
        /* disarm any ahg */
        qp->s_hdr->ahgcount = 0;
index a13a2b135365f845e825ec5a3cd105aaa13f4160..9beb0aa876f073c8eaad7fd119118b55b77dcf6c 100644 (file)
@@ -383,9 +383,7 @@ static int post_one_send(struct hfi1_qp *qp, struct ib_send_wr *wr)
         * undefined operations.
         * Make sure buffer is large enough to hold the result for atomics.
         */
-       if (wr->opcode == IB_WR_FAST_REG_MR) {
-               return -EINVAL;
-       } else if (qp->ibqp.qp_type == IB_QPT_UC) {
+       if (qp->ibqp.qp_type == IB_QPT_UC) {
                if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
                        return -EINVAL;
        } else if (qp->ibqp.qp_type != IB_QPT_RC) {
@@ -394,7 +392,7 @@ static int post_one_send(struct hfi1_qp *qp, struct ib_send_wr *wr)
                    wr->opcode != IB_WR_SEND_WITH_IMM)
                        return -EINVAL;
                /* Check UD destination address PD */
-               if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
                        return -EINVAL;
        } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
                return -EINVAL;
@@ -415,7 +413,21 @@ static int post_one_send(struct hfi1_qp *qp, struct ib_send_wr *wr)
        rkt = &to_idev(qp->ibqp.device)->lk_table;
        pd = to_ipd(qp->ibqp.pd);
        wqe = get_swqe_ptr(qp, qp->s_head);
-       wqe->wr = *wr;
+
+
+       if (qp->ibqp.qp_type != IB_QPT_UC &&
+           qp->ibqp.qp_type != IB_QPT_RC)
+               memcpy(&wqe->ud_wr, ud_wr(wr), sizeof(wqe->ud_wr));
+       else if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                wr->opcode == IB_WR_RDMA_WRITE ||
+                wr->opcode == IB_WR_RDMA_READ)
+               memcpy(&wqe->rdma_wr, rdma_wr(wr), sizeof(wqe->rdma_wr));
+       else if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+               memcpy(&wqe->atomic_wr, atomic_wr(wr), sizeof(wqe->atomic_wr));
+       else
+               memcpy(&wqe->wr, wr, sizeof(wqe->wr));
+
        wqe->length = 0;
        j = 0;
        if (wr->num_sge) {
@@ -441,7 +453,7 @@ static int post_one_send(struct hfi1_qp *qp, struct ib_send_wr *wr)
                if (wqe->length > 0x80000000U)
                        goto bail_inval_free;
        } else {
-               struct hfi1_ah *ah = to_iah(wr->wr.ud.ah);
+               struct hfi1_ah *ah = to_iah(ud_wr(wr)->ah);
 
                atomic_inc(&ah->refcount);
        }
@@ -2055,8 +2067,6 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
        ibdev->reg_user_mr = hfi1_reg_user_mr;
        ibdev->dereg_mr = hfi1_dereg_mr;
        ibdev->alloc_mr = hfi1_alloc_mr;
-       ibdev->alloc_fast_reg_page_list = hfi1_alloc_fast_reg_page_list;
-       ibdev->free_fast_reg_page_list = hfi1_free_fast_reg_page_list;
        ibdev->alloc_fmr = hfi1_alloc_fmr;
        ibdev->map_phys_fmr = hfi1_map_phys_fmr;
        ibdev->unmap_fmr = hfi1_unmap_fmr;
index e4a8a0d4ccf8b64a3ccf0d3f083276d6320dd43b..041ad07ee699a05c571b833f0469970da4972cae 100644 (file)
@@ -348,7 +348,12 @@ struct hfi1_mr {
  * in qp->s_max_sge.
  */
 struct hfi1_swqe {
-       struct ib_send_wr wr;   /* don't use wr.sg_list */
+       union {
+               struct ib_send_wr wr;   /* don't use wr.sg_list */
+               struct ib_rdma_wr rdma_wr;
+               struct ib_atomic_wr atomic_wr;
+               struct ib_ud_wr ud_wr;
+       };
        u32 psn;                /* first packet sequence number */
        u32 lpsn;               /* last packet sequence number */
        u32 ssn;                /* send sequence number */
@@ -1021,13 +1026,6 @@ struct ib_mr *hfi1_alloc_mr(struct ib_pd *pd,
                            enum ib_mr_type mr_type,
                            u32 max_entries);
 
-struct ib_fast_reg_page_list *hfi1_alloc_fast_reg_page_list(
-                               struct ib_device *ibdev, int page_list_len);
-
-void hfi1_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl);
-
-int hfi1_fast_reg_mr(struct hfi1_qp *qp, struct ib_send_wr *wr);
-
 struct ib_fmr *hfi1_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
                              struct ib_fmr_attr *fmr_attr);
 
index 79b3dbc9717923bfdbc215e78e10fcf9feb43a06..d4aa53574e576c83024e39822038edbfd3565212 100644 (file)
@@ -350,9 +350,9 @@ int ipath_make_rc_req(struct ipath_qp *qp)
                                goto bail;
                        }
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / sizeof(u32);
                        wqe->lpsn = wqe->psn;
@@ -401,9 +401,9 @@ int ipath_make_rc_req(struct ipath_qp *qp)
                                wqe->lpsn = qp->s_next_psn++;
                        }
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        qp->s_state = OP(RDMA_READ_REQUEST);
                        hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
@@ -433,21 +433,21 @@ int ipath_make_rc_req(struct ipath_qp *qp)
                        if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
                                qp->s_state = OP(COMPARE_SWAP);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.swap);
+                                       wqe->atomic_wr.swap);
                                ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                        } else {
                                qp->s_state = OP(FETCH_ADD);
                                ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->wr.wr.atomic.compare_add);
+                                       wqe->atomic_wr.compare_add);
                                ohdr->u.atomic_eth.compare_data = 0;
                        }
                        ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr >> 32);
+                               wqe->atomic_wr.remote_addr >> 32);
                        ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
-                               wqe->wr.wr.atomic.remote_addr);
+                               wqe->atomic_wr.remote_addr);
                        ohdr->u.atomic_eth.rkey = cpu_to_be32(
-                               wqe->wr.wr.atomic.rkey);
+                               wqe->atomic_wr.rkey);
                        hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
                        ss = NULL;
                        len = 0;
@@ -567,9 +567,9 @@ int ipath_make_rc_req(struct ipath_qp *qp)
                ipath_init_restart(qp, wqe);
                len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
                ohdr->u.rc.reth.vaddr =
-                       cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len);
+                       cpu_to_be64(wqe->rdma_wr.remote_addr + len);
                ohdr->u.rc.reth.rkey =
-                       cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                       cpu_to_be32(wqe->rdma_wr.rkey);
                ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
                qp->s_state = OP(RDMA_READ_REQUEST);
                hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
index 2296832f94da868e3c2f884bfbcd2d9e94cc4fed..e541a01f1f6122575260e30a7a1dff5445cbdc15 100644 (file)
@@ -352,8 +352,8 @@ again:
                if (wqe->length == 0)
                        break;
                if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
-                                           wqe->wr.wr.rdma.remote_addr,
-                                           wqe->wr.wr.rdma.rkey,
+                                           wqe->rdma_wr.remote_addr,
+                                           wqe->rdma_wr.rkey,
                                            IB_ACCESS_REMOTE_WRITE)))
                        goto acc_err;
                break;
@@ -362,8 +362,8 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
                        goto inv_err;
                if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
-                                           wqe->wr.wr.rdma.remote_addr,
-                                           wqe->wr.wr.rdma.rkey,
+                                           wqe->rdma_wr.remote_addr,
+                                           wqe->rdma_wr.rkey,
                                            IB_ACCESS_REMOTE_READ)))
                        goto acc_err;
                qp->r_sge.sge = wqe->sg_list[0];
@@ -376,18 +376,18 @@ again:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
                if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
-                                           wqe->wr.wr.atomic.remote_addr,
-                                           wqe->wr.wr.atomic.rkey,
+                                           wqe->atomic_wr.remote_addr,
+                                           wqe->atomic_wr.rkey,
                                            IB_ACCESS_REMOTE_ATOMIC)))
                        goto acc_err;
                /* Perform atomic OP and save result. */
                maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
-               sdata = wqe->wr.wr.atomic.compare_add;
+               sdata = wqe->atomic_wr.compare_add;
                *(u64 *) sqp->s_sge.sge.vaddr =
                        (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
                        (u64) atomic64_add_return(sdata, maddr) - sdata :
                        (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
-                                     sdata, wqe->wr.wr.atomic.swap);
+                                     sdata, wqe->atomic_wr.swap);
                goto send_comp;
 
        default:
index 22e60998f1a7cacd3c9d2e841db946ae31b2e3cd..0246b30280b9c2bc2f673ffd6c980adefbadf39a 100644 (file)
@@ -126,9 +126,9 @@ int ipath_make_uc_req(struct ipath_qp *qp)
                case IB_WR_RDMA_WRITE:
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+                               cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->wr.wr.rdma.rkey);
+                               cpu_to_be32(wqe->rdma_wr.rkey);
                        ohdr->u.rc.reth.length = cpu_to_be32(len);
                        hwords += sizeof(struct ib_reth) / 4;
                        if (len > pmtu) {
index 33fcfe206bc90d4613d561f90c51a27c6dae013d..385d9410a51e01478bb5f060c2ecb5d8129ef80f 100644 (file)
@@ -64,7 +64,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
        u32 rlen;
        u32 length;
 
-       qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
+       qp = ipath_lookup_qpn(&dev->qp_table, swqe->ud_wr.remote_qpn);
        if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
                dev->n_pkt_drops++;
                goto done;
@@ -76,8 +76,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
         * qkey from the QP context instead of the WR (see 10.2.5).
         */
        if (unlikely(qp->ibqp.qp_num &&
-                    ((int) swqe->wr.wr.ud.remote_qkey < 0 ?
-                     sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) {
+                    ((int) swqe->ud_wr.remote_qkey < 0 ?
+                     sqp->qkey : swqe->ud_wr.remote_qkey) != qp->qkey)) {
                /* XXX OK to lose a count once in a while. */
                dev->qkey_violations++;
                dev->n_pkt_drops++;
@@ -174,7 +174,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
        } else
                spin_unlock_irqrestore(&rq->lock, flags);
 
-       ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(swqe->ud_wr.ah)->attr;
        if (ah_attr->ah_flags & IB_AH_GRH) {
                ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
                wc.wc_flags |= IB_WC_GRH;
@@ -224,7 +224,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
        wc.port_num = 1;
        /* Signal completion event if the solicited bit is set. */
        ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                      swqe->wr.send_flags & IB_SEND_SOLICITED);
+                      swqe->ud_wr.wr.send_flags & IB_SEND_SOLICITED);
 drop:
        if (atomic_dec_and_test(&qp->refcount))
                wake_up(&qp->wait);
@@ -279,7 +279,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                next_cur = 0;
 
        /* Construct the header. */
-       ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
+       ah_attr = &to_iah(wqe->ud_wr.ah)->attr;
        if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
                if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
                        dev->n_multicast_xmit++;
@@ -321,7 +321,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
        qp->s_wqe = wqe;
        qp->s_sge.sge = wqe->sg_list[0];
        qp->s_sge.sg_list = wqe->sg_list + 1;
-       qp->s_sge.num_sge = wqe->wr.num_sge;
+       qp->s_sge.num_sge = wqe->ud_wr.wr.num_sge;
 
        if (ah_attr->ah_flags & IB_AH_GRH) {
                /* Header size in 32-bit words. */
@@ -339,9 +339,9 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                lrh0 = IPATH_LRH_BTH;
                ohdr = &qp->s_hdr.u.oth;
        }
-       if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+       if (wqe->ud_wr.wr.opcode == IB_WR_SEND_WITH_IMM) {
                qp->s_hdrwords++;
-               ohdr->u.ud.imm_data = wqe->wr.ex.imm_data;
+               ohdr->u.ud.imm_data = wqe->ud_wr.wr.ex.imm_data;
                bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
        } else
                bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
@@ -359,7 +359,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                qp->s_hdr.lrh[3] = cpu_to_be16(lid);
        } else
                qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
-       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
+       if (wqe->ud_wr.wr.send_flags & IB_SEND_SOLICITED)
                bth0 |= 1 << 23;
        bth0 |= extra_bytes << 20;
        bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
@@ -371,14 +371,14 @@ int ipath_make_ud_req(struct ipath_qp *qp)
        ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
                ah_attr->dlid != IPATH_PERMISSIVE_LID ?
                cpu_to_be32(IPATH_MULTICAST_QPN) :
-               cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
+               cpu_to_be32(wqe->ud_wr.remote_qpn);
        ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
        /*
         * Qkeys with the high order bit set mean use the
         * qkey from the QP context instead of the WR (see 10.2.5).
         */
-       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
-                                        qp->qkey : wqe->wr.wr.ud.remote_qkey);
+       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
+                                        qp->qkey : wqe->ud_wr.remote_qkey);
        ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
 
 done:
index a2fb41bba11711828a9d17e5cbc0c5398c5ee7a5..1778dee13f99269c51cc90f6c4d09a6f46a13a21 100644 (file)
@@ -374,7 +374,7 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
                    wr->opcode != IB_WR_SEND_WITH_IMM)
                        goto bail_inval;
                /* Check UD destination address PD */
-               if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
                        goto bail_inval;
        } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
                goto bail_inval;
@@ -395,7 +395,20 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
        }
 
        wqe = get_swqe_ptr(qp, qp->s_head);
-       wqe->wr = *wr;
+
+       if (qp->ibqp.qp_type != IB_QPT_UC &&
+           qp->ibqp.qp_type != IB_QPT_RC)
+               memcpy(&wqe->ud_wr, ud_wr(wr), sizeof(wqe->ud_wr));
+       else if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                wr->opcode == IB_WR_RDMA_WRITE ||
+                wr->opcode == IB_WR_RDMA_READ)
+               memcpy(&wqe->rdma_wr, rdma_wr(wr), sizeof(wqe->rdma_wr));
+       else if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+                wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+               memcpy(&wqe->atomic_wr, atomic_wr(wr), sizeof(wqe->atomic_wr));
+       else
+               memcpy(&wqe->wr, wr, sizeof(wqe->wr));
+
        wqe->length = 0;
        if (wr->num_sge) {
                acc = wr->opcode >= IB_WR_RDMA_READ ?
index ec167e545e15c3df3d9d61dbad49d7152bbe3846..0a90a56870ab0653022b098d2eda6df510b59ad0 100644 (file)
@@ -277,7 +277,13 @@ struct ipath_mr {
  * in qp->s_max_sge.
  */
 struct ipath_swqe {
-       struct ib_send_wr wr;   /* don't use wr.sg_list */
+       union {
+               struct ib_send_wr wr;   /* don't use wr.sg_list */
+               struct ib_ud_wr ud_wr;
+               struct ib_rdma_wr rdma_wr;
+               struct ib_atomic_wr atomic_wr;
+       };
+
        u32 psn;                /* first packet sequence number */
        u32 lpsn;               /* last packet sequence number */
        u32 ssn;                /* send sequence number */
index 1f063d3aa32fe43234c10922354f7a9d44c19489..ac5716979bc12b0024ff1636d66bee07175a88a0 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/string.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <asm-generic/bug.h>
+#include <linux/bug.h>
 #include "n_tracesink.h"
 
 /*
index ddce58b973d2017c812c78f073af35f660e42d76..4616870a6b1b96c4755c8fffee9e9a7256590ff2 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/tty_ldisc.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <asm-generic/bug.h>
+#include <linux/bug.h>
 #include "n_tracesink.h"
 
 /*
index be9048e2d4d4f1cc4f40003e89c2553358420122..0b9451250e33f5f82fd52f00cf05338849b81e7c 100644 (file)
@@ -28,8 +28,7 @@
 #include <linux/timer.h>
 #include <linux/kernel.h>
 #include <linux/usb/hcd.h>
-
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 
 /* Code sharing between pci-quirks and xhci hcd */
 #include       "xhci-ext-caps.h"
index f79cf4043e60d9c854adfce1634164e1a0fef53f..79f522575cba3e79e6909ca4c1c055d2cb54ce9a 100644 (file)
@@ -63,10 +63,11 @@ obj-$(CONFIG_DLM)           += dlm/
 # Do not add any filesystems before this line
 obj-$(CONFIG_FSCACHE)          += fscache/
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
-obj-$(CONFIG_EXT2_FS)          += ext2/
-# We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2
-# unless explicitly requested by rootfstype
 obj-$(CONFIG_EXT4_FS)          += ext4/
+# We place ext4 before ext2 so that clean ext3 root fs's do NOT mount using the
+# ext2 driver, which doesn't know about journalling!  Explicitly request ext2
+# by giving the rootfstype= parameter.
+obj-$(CONFIG_EXT2_FS)          += ext2/
 obj-$(CONFIG_JBD2)             += jbd2/
 obj-$(CONFIG_CRAMFS)           += cramfs/
 obj-$(CONFIG_SQUASHFS)         += squashfs/
index 9a2ec79e8cfb6c4ad26a5578e39f62f8fa80226b..6dcdb2ec921185ae350aa0f2ff49cd65eaa0d500 100644 (file)
@@ -362,6 +362,12 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
                goto out;
        }
 
+       if (btrfs_test_is_dummy_root(root)) {
+               srcu_read_unlock(&fs_info->subvol_srcu, index);
+               ret = -ENOENT;
+               goto out;
+       }
+
        if (path->search_commit_root)
                root_level = btrfs_header_level(root->commit_root);
        else if (time_seq == (u64)-1)
index 541fbfaed2763a836da04ce8076d43af359558bb..0340c57bf37778f6983645803c3f381ae1a27a2a 100644 (file)
@@ -667,7 +667,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
        selected_super = kzalloc(sizeof(*selected_super), GFP_NOFS);
        if (NULL == selected_super) {
                printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
-               return -1;
+               return -ENOMEM;
        }
 
        list_for_each_entry(device, dev_head, dev_list) {
@@ -845,8 +845,8 @@ static int btrfsic_process_superblock_dev_mirror(
                superblock_tmp->never_written = 0;
                superblock_tmp->mirror_num = 1 + superblock_mirror_num;
                if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE)
-                       printk_in_rcu(KERN_INFO "New initial S-block (bdev %p, %s)"
-                                    " @%llu (%s/%llu/%d)\n",
+                       btrfs_info_in_rcu(device->dev_root->fs_info,
+                               "new initial S-block (bdev %p, %s) @%llu (%s/%llu/%d)",
                                     superblock_bdev,
                                     rcu_str_deref(device->name), dev_bytenr,
                                     dev_state->name, dev_bytenr,
@@ -1660,7 +1660,7 @@ static int btrfsic_read_block(struct btrfsic_state *state,
                                          sizeof(*block_ctx->pagev)) *
                                         num_pages, GFP_NOFS);
        if (!block_ctx->mem_to_free)
-               return -1;
+               return -ENOMEM;
        block_ctx->datav = block_ctx->mem_to_free;
        block_ctx->pagev = (struct page **)(block_ctx->datav + num_pages);
        for (i = 0; i < num_pages; i++) {
index 36dfeff2c1f443aade91be4ccbce56bec9317008..c473c42d7d6c4d559dbe1587491cd2fb93804145 100644 (file)
@@ -744,11 +744,13 @@ out:
        return ret;
 }
 
-static struct list_head comp_idle_workspace[BTRFS_COMPRESS_TYPES];
-static spinlock_t comp_workspace_lock[BTRFS_COMPRESS_TYPES];
-static int comp_num_workspace[BTRFS_COMPRESS_TYPES];
-static atomic_t comp_alloc_workspace[BTRFS_COMPRESS_TYPES];
-static wait_queue_head_t comp_workspace_wait[BTRFS_COMPRESS_TYPES];
+static struct {
+       struct list_head idle_ws;
+       spinlock_t ws_lock;
+       int num_ws;
+       atomic_t alloc_ws;
+       wait_queue_head_t ws_wait;
+} btrfs_comp_ws[BTRFS_COMPRESS_TYPES];
 
 static const struct btrfs_compress_op * const btrfs_compress_op[] = {
        &btrfs_zlib_compress,
@@ -760,10 +762,10 @@ void __init btrfs_init_compress(void)
        int i;
 
        for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) {
-               INIT_LIST_HEAD(&comp_idle_workspace[i]);
-               spin_lock_init(&comp_workspace_lock[i]);
-               atomic_set(&comp_alloc_workspace[i], 0);
-               init_waitqueue_head(&comp_workspace_wait[i]);
+               INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws);
+               spin_lock_init(&btrfs_comp_ws[i].ws_lock);
+               atomic_set(&btrfs_comp_ws[i].alloc_ws, 0);
+               init_waitqueue_head(&btrfs_comp_ws[i].ws_wait);
        }
 }
 
@@ -777,38 +779,38 @@ static struct list_head *find_workspace(int type)
        int cpus = num_online_cpus();
        int idx = type - 1;
 
-       struct list_head *idle_workspace        = &comp_idle_workspace[idx];
-       spinlock_t *workspace_lock              = &comp_workspace_lock[idx];
-       atomic_t *alloc_workspace               = &comp_alloc_workspace[idx];
-       wait_queue_head_t *workspace_wait       = &comp_workspace_wait[idx];
-       int *num_workspace                      = &comp_num_workspace[idx];
+       struct list_head *idle_ws       = &btrfs_comp_ws[idx].idle_ws;
+       spinlock_t *ws_lock             = &btrfs_comp_ws[idx].ws_lock;
+       atomic_t *alloc_ws              = &btrfs_comp_ws[idx].alloc_ws;
+       wait_queue_head_t *ws_wait      = &btrfs_comp_ws[idx].ws_wait;
+       int *num_ws                     = &btrfs_comp_ws[idx].num_ws;
 again:
-       spin_lock(workspace_lock);
-       if (!list_empty(idle_workspace)) {
-               workspace = idle_workspace->next;
+       spin_lock(ws_lock);
+       if (!list_empty(idle_ws)) {
+               workspace = idle_ws->next;
                list_del(workspace);
-               (*num_workspace)--;
-               spin_unlock(workspace_lock);
+               (*num_ws)--;
+               spin_unlock(ws_lock);
                return workspace;
 
        }
-       if (atomic_read(alloc_workspace) > cpus) {
+       if (atomic_read(alloc_ws) > cpus) {
                DEFINE_WAIT(wait);
 
-               spin_unlock(workspace_lock);
-               prepare_to_wait(workspace_wait, &wait, TASK_UNINTERRUPTIBLE);
-               if (atomic_read(alloc_workspace) > cpus && !*num_workspace)
+               spin_unlock(ws_lock);
+               prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE);
+               if (atomic_read(alloc_ws) > cpus && !*num_ws)
                        schedule();
-               finish_wait(workspace_wait, &wait);
+               finish_wait(ws_wait, &wait);
                goto again;
        }
-       atomic_inc(alloc_workspace);
-       spin_unlock(workspace_lock);
+       atomic_inc(alloc_ws);
+       spin_unlock(ws_lock);
 
        workspace = btrfs_compress_op[idx]->alloc_workspace();
        if (IS_ERR(workspace)) {
-               atomic_dec(alloc_workspace);
-               wake_up(workspace_wait);
+               atomic_dec(alloc_ws);
+               wake_up(ws_wait);
        }
        return workspace;
 }
@@ -820,27 +822,30 @@ again:
 static void free_workspace(int type, struct list_head *workspace)
 {
        int idx = type - 1;
-       struct list_head *idle_workspace        = &comp_idle_workspace[idx];
-       spinlock_t *workspace_lock              = &comp_workspace_lock[idx];
-       atomic_t *alloc_workspace               = &comp_alloc_workspace[idx];
-       wait_queue_head_t *workspace_wait       = &comp_workspace_wait[idx];
-       int *num_workspace                      = &comp_num_workspace[idx];
-
-       spin_lock(workspace_lock);
-       if (*num_workspace < num_online_cpus()) {
-               list_add(workspace, idle_workspace);
-               (*num_workspace)++;
-               spin_unlock(workspace_lock);
+       struct list_head *idle_ws       = &btrfs_comp_ws[idx].idle_ws;
+       spinlock_t *ws_lock             = &btrfs_comp_ws[idx].ws_lock;
+       atomic_t *alloc_ws              = &btrfs_comp_ws[idx].alloc_ws;
+       wait_queue_head_t *ws_wait      = &btrfs_comp_ws[idx].ws_wait;
+       int *num_ws                     = &btrfs_comp_ws[idx].num_ws;
+
+       spin_lock(ws_lock);
+       if (*num_ws < num_online_cpus()) {
+               list_add(workspace, idle_ws);
+               (*num_ws)++;
+               spin_unlock(ws_lock);
                goto wake;
        }
-       spin_unlock(workspace_lock);
+       spin_unlock(ws_lock);
 
        btrfs_compress_op[idx]->free_workspace(workspace);
-       atomic_dec(alloc_workspace);
+       atomic_dec(alloc_ws);
 wake:
+       /*
+        * Make sure counter is updated before we wake up waiters.
+        */
        smp_mb();
-       if (waitqueue_active(workspace_wait))
-               wake_up(workspace_wait);
+       if (waitqueue_active(ws_wait))
+               wake_up(ws_wait);
 }
 
 /*
@@ -852,11 +857,11 @@ static void free_workspaces(void)
        int i;
 
        for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) {
-               while (!list_empty(&comp_idle_workspace[i])) {
-                       workspace = comp_idle_workspace[i].next;
+               while (!list_empty(&btrfs_comp_ws[i].idle_ws)) {
+                       workspace = btrfs_comp_ws[i].idle_ws.next;
                        list_del(workspace);
                        btrfs_compress_op[i]->free_workspace(workspace);
-                       atomic_dec(&comp_alloc_workspace[i]);
+                       atomic_dec(&btrfs_comp_ws[i].alloc_ws);
                }
        }
 }
index 5f745eadf77dd07454ccb0c1d201124738cb4edc..5b8e235c4b6d6299183ebba91976f0d53612c16c 100644 (file)
@@ -1011,7 +1011,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                        return ret;
                if (refs == 0) {
                        ret = -EROFS;
-                       btrfs_std_error(root->fs_info, ret);
+                       btrfs_std_error(root->fs_info, ret, NULL);
                        return ret;
                }
        } else {
@@ -1927,7 +1927,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                child = read_node_slot(root, mid, 0);
                if (!child) {
                        ret = -EROFS;
-                       btrfs_std_error(root->fs_info, ret);
+                       btrfs_std_error(root->fs_info, ret, NULL);
                        goto enospc;
                }
 
@@ -2030,7 +2030,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                 */
                if (!left) {
                        ret = -EROFS;
-                       btrfs_std_error(root->fs_info, ret);
+                       btrfs_std_error(root->fs_info, ret, NULL);
                        goto enospc;
                }
                wret = balance_node_right(trans, root, mid, left);
@@ -4940,8 +4940,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 {
        struct extent_buffer *leaf;
        struct btrfs_item *item;
-       int last_off;
-       int dsize = 0;
+       u32 last_off;
+       u32 dsize = 0;
        int ret = 0;
        int wret;
        int i;
index eb90f0f1a12428827ad84a52fcb32f44ee3d289d..8c58191249cc14c33c376bb0c8c0a469cb95b894 100644 (file)
@@ -823,8 +823,18 @@ struct btrfs_disk_balance_args {
         */
        __le64 profiles;
 
-       /* usage filter */
-       __le64 usage;
+       /*
+        * usage filter
+        * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N'
+        * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max
+        */
+       union {
+               __le64 usage;
+               struct {
+                       __le32 usage_min;
+                       __le32 usage_max;
+               };
+       };
 
        /* devid filter */
        __le64 devid;
@@ -846,10 +856,27 @@ struct btrfs_disk_balance_args {
        /* BTRFS_BALANCE_ARGS_* */
        __le64 flags;
 
-       /* BTRFS_BALANCE_ARGS_LIMIT value */
-       __le64 limit;
+       /*
+        * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+        * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
+        * and maximum
+        */
+       union {
+               __le64 limit;
+               struct {
+                       __le32 limit_min;
+                       __le32 limit_max;
+               };
+       };
 
-       __le64 unused[7];
+       /*
+        * Process chunks that cross stripes_min..stripes_max devices,
+        * BTRFS_BALANCE_ARGS_STRIPES_RANGE
+        */
+       __le32 stripes_min;
+       __le32 stripes_max;
+
+       __le64 unused[6];
 } __attribute__ ((__packed__));
 
 /*
@@ -1154,6 +1181,10 @@ struct btrfs_space_info {
                                   delalloc/allocations */
        u64 bytes_readonly;     /* total bytes that are read only */
 
+       u64 max_extent_size;    /* This will hold the maximum extent size of
+                                  the space info if we had an ENOSPC in the
+                                  allocator. */
+
        unsigned int full:1;    /* indicates that we cannot allocate any more
                                   chunks for this space */
        unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
@@ -1228,6 +1259,9 @@ struct btrfs_free_cluster {
        /* first extent starting offset */
        u64 window_start;
 
+       /* We did a full search and couldn't create a cluster */
+       bool fragmented;
+
        struct btrfs_block_group_cache *block_group;
        /*
         * when a cluster is allocated from a block group, we put the
@@ -1943,6 +1977,9 @@ struct btrfs_root {
        int send_in_progress;
        struct btrfs_subvolume_writers *subv_writers;
        atomic_t will_be_snapshoted;
+
+       /* For qgroup metadata space reserve */
+       atomic_t qgroup_meta_rsv;
 };
 
 struct btrfs_ioctl_defrag_range_args {
@@ -2145,6 +2182,8 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
 #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR       (1 << 22)
 #define BTRFS_MOUNT_RESCAN_UUID_TREE   (1 << 23)
+#define BTRFS_MOUNT_FRAGMENT_DATA      (1 << 24)
+#define BTRFS_MOUNT_FRAGMENT_METADATA  (1 << 25)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
 #define BTRFS_DEFAULT_MAX_INLINE       (8192)
@@ -2169,6 +2208,18 @@ struct btrfs_ioctl_defrag_range_args {
        btrfs_clear_opt(root->fs_info->mount_opt, opt);                 \
 }
 
+#ifdef CONFIG_BTRFS_DEBUG
+static inline int
+btrfs_should_fragment_free_space(struct btrfs_root *root,
+                                struct btrfs_block_group_cache *block_group)
+{
+       return (btrfs_test_opt(root, FRAGMENT_METADATA) &&
+               block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+              (btrfs_test_opt(root, FRAGMENT_DATA) &&
+               block_group->flags &  BTRFS_BLOCK_GROUP_DATA);
+}
+#endif
+
 /*
  * Requests for changes that need to be done during transaction commit.
  *
@@ -3379,7 +3430,8 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
 int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 root_objectid, u64 owner,
-                                    u64 offset, struct btrfs_key *ins);
+                                    u64 offset, u64 ram_bytes,
+                                    struct btrfs_key *ins);
 int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   u64 root_objectid, u64 owner, u64 offset,
@@ -3398,7 +3450,7 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
 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 no_quota);
+                     u64 owner, u64 offset);
 
 int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len,
                               int delalloc);
@@ -3411,7 +3463,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, int no_quota);
+                        u64 root_objectid, u64 owner, u64 offset);
 
 int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root);
@@ -3449,8 +3501,11 @@ enum btrfs_reserve_flush_enum {
        BTRFS_RESERVE_FLUSH_ALL,
 };
 
-int btrfs_check_data_free_space(struct inode *inode, u64 bytes, u64 write_bytes);
-void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
+int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len);
+int btrfs_alloc_data_chunk_ondemand(struct inode *inode, u64 bytes);
+void btrfs_free_reserved_data_space(struct inode *inode, u64 start, u64 len);
+void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
+                                           u64 len);
 void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root);
 void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
@@ -3466,8 +3521,8 @@ void btrfs_subvolume_release_metadata(struct btrfs_root *root,
                                      u64 qgroup_reserved);
 int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes);
 void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes);
-int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes);
-void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes);
+int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len);
+void btrfs_delalloc_release_space(struct inode *inode, u64 start, u64 len);
 void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
 struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root,
                                              unsigned short type);
@@ -4004,8 +4059,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 /* sysfs.c */
 int btrfs_init_sysfs(void);
 void btrfs_exit_sysfs(void);
-int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info);
-void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info);
+int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info);
+void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);
 
 /* xattr.c */
 ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
@@ -4039,14 +4094,102 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
 #define btrfs_info(fs_info, fmt, args...) \
        btrfs_printk(fs_info, KERN_INFO fmt, ##args)
 
+/*
+ * Wrappers that use printk_in_rcu
+ */
+#define btrfs_emerg_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_INFO fmt, ##args)
+
+/*
+ * Wrappers that use a ratelimited printk_in_rcu
+ */
+#define btrfs_emerg_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_INFO fmt, ##args)
+
+/*
+ * Wrappers that use a ratelimited printk
+ */
+#define btrfs_emerg_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_EMERG fmt, ##args)
+#define btrfs_alert_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_ALERT fmt, ##args)
+#define btrfs_crit_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_CRIT fmt, ##args)
+#define btrfs_err_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_ERR fmt, ##args)
+#define btrfs_warn_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_WARNING fmt, ##args)
+#define btrfs_notice_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_NOTICE fmt, ##args)
+#define btrfs_info_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_INFO fmt, ##args)
 #ifdef DEBUG
 #define btrfs_debug(fs_info, fmt, args...) \
        btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
+       btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl(fs_info, fmt, args...) \
+       btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, ##args)
 #else
 #define btrfs_debug(fs_info, fmt, args...) \
     no_printk(KERN_DEBUG fmt, ##args)
+#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
+       no_printk(KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
+       no_printk(KERN_DEBUG fmt, ##args)
+#define btrfs_debug_rl(fs_info, fmt, args...) \
+       no_printk(KERN_DEBUG fmt, ##args)
 #endif
 
+#define btrfs_printk_in_rcu(fs_info, fmt, args...)     \
+do {                                                   \
+       rcu_read_lock();                                \
+       btrfs_printk(fs_info, fmt, ##args);             \
+       rcu_read_unlock();                              \
+} while (0)
+
+#define btrfs_printk_ratelimited(fs_info, fmt, args...)                \
+do {                                                           \
+       static DEFINE_RATELIMIT_STATE(_rs,                      \
+               DEFAULT_RATELIMIT_INTERVAL,                     \
+               DEFAULT_RATELIMIT_BURST);                       \
+       if (__ratelimit(&_rs))                                  \
+               btrfs_printk(fs_info, fmt, ##args);             \
+} while (0)
+
+#define btrfs_printk_rl_in_rcu(fs_info, fmt, args...)          \
+do {                                                           \
+       rcu_read_lock();                                        \
+       btrfs_printk_ratelimited(fs_info, fmt, ##args);         \
+       rcu_read_unlock();                                      \
+} while (0)
+
 #ifdef CONFIG_BTRFS_ASSERT
 
 __cold
@@ -4127,14 +4270,7 @@ do {                                                             \
                                  __LINE__, (errno));           \
 } while (0)
 
-#define btrfs_std_error(fs_info, errno)                                \
-do {                                                           \
-       if ((errno))                                            \
-               __btrfs_std_error((fs_info), __func__,          \
-                                  __LINE__, (errno), NULL);    \
-} while (0)
-
-#define btrfs_error(fs_info, errno, fmt, args...)              \
+#define btrfs_std_error(fs_info, errno, fmt, args...)          \
 do {                                                           \
        __btrfs_std_error((fs_info), __func__, __LINE__,        \
                          (errno), fmt, ##args);                \
index a2ae42720a6afe92701de402b837d56dd66d03b4..e0941fbb913c2e99740b9df34d06efbc8cffdea1 100644 (file)
@@ -463,6 +463,10 @@ static int __btrfs_add_delayed_deletion_item(struct btrfs_delayed_node *node,
 static void finish_one_item(struct btrfs_delayed_root *delayed_root)
 {
        int seq = atomic_inc_return(&delayed_root->items_seq);
+
+       /*
+        * atomic_dec_return implies a barrier for waitqueue_active
+        */
        if ((atomic_dec_return(&delayed_root->items) <
            BTRFS_DELAYED_BACKGROUND || seq % BTRFS_DELAYED_BATCH == 0) &&
            waitqueue_active(&delayed_root->wait))
index ac3e81da6d4edc8e33856840349cc88750771546..e06dd75ad13f98999682c00128ae852e0a886e14 100644 (file)
@@ -197,6 +197,119 @@ static inline void drop_delayed_ref(struct btrfs_trans_handle *trans,
                trans->delayed_ref_updates--;
 }
 
+static bool merge_ref(struct btrfs_trans_handle *trans,
+                     struct btrfs_delayed_ref_root *delayed_refs,
+                     struct btrfs_delayed_ref_head *head,
+                     struct btrfs_delayed_ref_node *ref,
+                     u64 seq)
+{
+       struct btrfs_delayed_ref_node *next;
+       bool done = false;
+
+       next = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node,
+                               list);
+       while (!done && &next->list != &head->ref_list) {
+               int mod;
+               struct btrfs_delayed_ref_node *next2;
+
+               next2 = list_next_entry(next, list);
+
+               if (next == ref)
+                       goto next;
+
+               if (seq && next->seq >= seq)
+                       goto next;
+
+               if (next->type != ref->type)
+                       goto next;
+
+               if ((ref->type == BTRFS_TREE_BLOCK_REF_KEY ||
+                    ref->type == BTRFS_SHARED_BLOCK_REF_KEY) &&
+                   comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref),
+                                  btrfs_delayed_node_to_tree_ref(next),
+                                  ref->type))
+                       goto next;
+               if ((ref->type == BTRFS_EXTENT_DATA_REF_KEY ||
+                    ref->type == BTRFS_SHARED_DATA_REF_KEY) &&
+                   comp_data_refs(btrfs_delayed_node_to_data_ref(ref),
+                                  btrfs_delayed_node_to_data_ref(next)))
+                       goto next;
+
+               if (ref->action == next->action) {
+                       mod = next->ref_mod;
+               } else {
+                       if (ref->ref_mod < next->ref_mod) {
+                               swap(ref, next);
+                               done = true;
+                       }
+                       mod = -next->ref_mod;
+               }
+
+               drop_delayed_ref(trans, delayed_refs, head, next);
+               ref->ref_mod += mod;
+               if (ref->ref_mod == 0) {
+                       drop_delayed_ref(trans, delayed_refs, head, ref);
+                       done = true;
+               } else {
+                       /*
+                        * Can't have multiples of the same ref on a tree block.
+                        */
+                       WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY ||
+                               ref->type == BTRFS_SHARED_BLOCK_REF_KEY);
+               }
+next:
+               next = next2;
+       }
+
+       return done;
+}
+
+void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
+                             struct btrfs_fs_info *fs_info,
+                             struct btrfs_delayed_ref_root *delayed_refs,
+                             struct btrfs_delayed_ref_head *head)
+{
+       struct btrfs_delayed_ref_node *ref;
+       u64 seq = 0;
+
+       assert_spin_locked(&head->lock);
+
+       if (list_empty(&head->ref_list))
+               return;
+
+       /* We don't have too many refs to merge for data. */
+       if (head->is_data)
+               return;
+
+       spin_lock(&fs_info->tree_mod_seq_lock);
+       if (!list_empty(&fs_info->tree_mod_seq_list)) {
+               struct seq_list *elem;
+
+               elem = list_first_entry(&fs_info->tree_mod_seq_list,
+                                       struct seq_list, list);
+               seq = elem->seq;
+       }
+       spin_unlock(&fs_info->tree_mod_seq_lock);
+
+       ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node,
+                              list);
+       while (&ref->list != &head->ref_list) {
+               if (seq && ref->seq >= seq)
+                       goto next;
+
+               if (merge_ref(trans, delayed_refs, head, ref, seq)) {
+                       if (list_empty(&head->ref_list))
+                               break;
+                       ref = list_first_entry(&head->ref_list,
+                                              struct btrfs_delayed_ref_node,
+                                              list);
+                       continue;
+               }
+next:
+               ref = list_next_entry(ref, list);
+       }
+}
+
 int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
                            struct btrfs_delayed_ref_root *delayed_refs,
                            u64 seq)
@@ -292,8 +405,7 @@ add_delayed_ref_tail_merge(struct btrfs_trans_handle *trans,
        exist = list_entry(href->ref_list.prev, struct btrfs_delayed_ref_node,
                           list);
        /* No need to compare bytenr nor is_head */
-       if (exist->type != ref->type || exist->no_quota != ref->no_quota ||
-           exist->seq != ref->seq)
+       if (exist->type != ref->type || exist->seq != ref->seq)
                goto add_tail;
 
        if ((exist->type == BTRFS_TREE_BLOCK_REF_KEY ||
@@ -423,7 +535,8 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
                     struct btrfs_trans_handle *trans,
                     struct btrfs_delayed_ref_node *ref,
                     struct btrfs_qgroup_extent_record *qrecord,
-                    u64 bytenr, u64 num_bytes, int action, int is_data)
+                    u64 bytenr, u64 num_bytes, u64 ref_root, u64 reserved,
+                    int action, int is_data)
 {
        struct btrfs_delayed_ref_head *existing;
        struct btrfs_delayed_ref_head *head_ref = NULL;
@@ -432,6 +545,9 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        int count_mod = 1;
        int must_insert_reserved = 0;
 
+       /* If reserved is provided, it must be a data extent. */
+       BUG_ON(!is_data && reserved);
+
        /*
         * the head node stores the sum of all the mods, so dropping a ref
         * should drop the sum in the head node by one.
@@ -476,9 +592,16 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        INIT_LIST_HEAD(&head_ref->ref_list);
        head_ref->processing = 0;
        head_ref->total_ref_mod = count_mod;
+       head_ref->qgroup_reserved = 0;
+       head_ref->qgroup_ref_root = 0;
 
        /* Record qgroup extent info if provided */
        if (qrecord) {
+               if (ref_root && reserved) {
+                       head_ref->qgroup_ref_root = ref_root;
+                       head_ref->qgroup_reserved = reserved;
+               }
+
                qrecord->bytenr = bytenr;
                qrecord->num_bytes = num_bytes;
                qrecord->old_roots = NULL;
@@ -497,6 +620,8 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        existing = htree_insert(&delayed_refs->href_root,
                                &head_ref->href_node);
        if (existing) {
+               WARN_ON(ref_root && reserved && existing->qgroup_ref_root
+                       && existing->qgroup_reserved);
                update_existing_head_ref(delayed_refs, &existing->node, ref);
                /*
                 * we've updated the existing ref, free the newly
@@ -524,7 +649,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
                     struct btrfs_delayed_ref_head *head_ref,
                     struct btrfs_delayed_ref_node *ref, u64 bytenr,
                     u64 num_bytes, u64 parent, u64 ref_root, int level,
-                    int action, int no_quota)
+                    int action)
 {
        struct btrfs_delayed_tree_ref *full_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
@@ -546,7 +671,6 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
        ref->action = action;
        ref->is_head = 0;
        ref->in_tree = 1;
-       ref->no_quota = no_quota;
        ref->seq = seq;
 
        full_ref = btrfs_delayed_node_to_tree_ref(ref);
@@ -579,7 +703,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
                     struct btrfs_delayed_ref_head *head_ref,
                     struct btrfs_delayed_ref_node *ref, u64 bytenr,
                     u64 num_bytes, u64 parent, u64 ref_root, u64 owner,
-                    u64 offset, int action, int no_quota)
+                    u64 offset, int action)
 {
        struct btrfs_delayed_data_ref *full_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
@@ -602,7 +726,6 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
        ref->action = action;
        ref->is_head = 0;
        ref->in_tree = 1;
-       ref->no_quota = no_quota;
        ref->seq = seq;
 
        full_ref = btrfs_delayed_node_to_data_ref(ref);
@@ -633,17 +756,13 @@ 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 no_quota)
+                              struct btrfs_delayed_extent_op *extent_op)
 {
        struct btrfs_delayed_tree_ref *ref;
        struct btrfs_delayed_ref_head *head_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
        struct btrfs_qgroup_extent_record *record = NULL;
 
-       if (!is_fstree(ref_root) || !fs_info->quota_enabled)
-               no_quota = 0;
-
        BUG_ON(extent_op && extent_op->is_data);
        ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS);
        if (!ref)
@@ -669,11 +788,10 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
         * the spin lock
         */
        head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node, record,
-                                       bytenr, num_bytes, action, 0);
+                                       bytenr, num_bytes, 0, 0, action, 0);
 
        add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr,
-                                  num_bytes, parent, ref_root, level, action,
-                                  no_quota);
+                            num_bytes, parent, ref_root, level, action);
        spin_unlock(&delayed_refs->lock);
 
        return 0;
@@ -693,18 +811,14 @@ 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 no_quota)
+                              u64 owner, u64 offset, u64 reserved, int action,
+                              struct btrfs_delayed_extent_op *extent_op)
 {
        struct btrfs_delayed_data_ref *ref;
        struct btrfs_delayed_ref_head *head_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
        struct btrfs_qgroup_extent_record *record = NULL;
 
-       if (!is_fstree(ref_root) || !fs_info->quota_enabled)
-               no_quota = 0;
-
        BUG_ON(extent_op && !extent_op->is_data);
        ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS);
        if (!ref)
@@ -736,16 +850,44 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
         * the spin lock
         */
        head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node, record,
-                                       bytenr, num_bytes, action, 1);
+                                       bytenr, num_bytes, ref_root, reserved,
+                                       action, 1);
 
        add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr,
                                   num_bytes, parent, ref_root, owner, offset,
-                                  action, no_quota);
+                                  action);
        spin_unlock(&delayed_refs->lock);
 
        return 0;
 }
 
+int btrfs_add_delayed_qgroup_reserve(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_trans_handle *trans,
+                                    u64 ref_root, u64 bytenr, u64 num_bytes)
+{
+       struct btrfs_delayed_ref_root *delayed_refs;
+       struct btrfs_delayed_ref_head *ref_head;
+       int ret = 0;
+
+       if (!fs_info->quota_enabled || !is_fstree(ref_root))
+               return 0;
+
+       delayed_refs = &trans->transaction->delayed_refs;
+
+       spin_lock(&delayed_refs->lock);
+       ref_head = find_ref_head(&delayed_refs->href_root, bytenr, 0);
+       if (!ref_head) {
+               ret = -ENOENT;
+               goto out;
+       }
+       WARN_ON(ref_head->qgroup_reserved || ref_head->qgroup_ref_root);
+       ref_head->qgroup_ref_root = ref_root;
+       ref_head->qgroup_reserved = num_bytes;
+out:
+       spin_unlock(&delayed_refs->lock);
+       return ret;
+}
+
 int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
                                struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
@@ -764,7 +906,7 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
        spin_lock(&delayed_refs->lock);
 
        add_delayed_ref_head(fs_info, trans, &head_ref->node, NULL, bytenr,
-                            num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
+                            num_bytes, 0, 0, BTRFS_UPDATE_DELAYED_HEAD,
                             extent_op->is_data);
 
        spin_unlock(&delayed_refs->lock);
index 13fb5e6090fe0efc7f55dc9b09e9faac57a3c91b..00ed02cbf3e903a708dd55a4c232a911241da2a8 100644 (file)
@@ -68,7 +68,6 @@ struct btrfs_delayed_ref_node {
 
        unsigned int action:8;
        unsigned int type:8;
-       unsigned int no_quota:1;
        /* is this node still in the rbtree? */
        unsigned int is_head:1;
        unsigned int in_tree:1;
@@ -112,6 +111,17 @@ struct btrfs_delayed_ref_head {
         */
        int total_ref_mod;
 
+       /*
+        * For qgroup reserved space freeing.
+        *
+        * ref_root and reserved will be recorded after
+        * BTRFS_ADD_DELAYED_EXTENT is called.
+        * And will be used to free reserved qgroup space at
+        * run_delayed_refs() time.
+        */
+       u64 qgroup_ref_root;
+       u64 qgroup_reserved;
+
        /*
         * when a new extent is allocated, it is just reserved in memory
         * The actual extent isn't inserted into the extent allocation tree
@@ -233,15 +243,16 @@ 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 no_quota);
+                              struct btrfs_delayed_extent_op *extent_op);
 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 no_quota);
+                              u64 owner, u64 offset, u64 reserved, int action,
+                              struct btrfs_delayed_extent_op *extent_op);
+int btrfs_add_delayed_qgroup_reserve(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_trans_handle *trans,
+                                    u64 ref_root, u64 bytenr, u64 num_bytes);
 int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
                                struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
index e54dd5905cee177912e03c915a8d471762bfc0cd..1e668fb7dd4c73dbc03b7f642660f2af20bd2ddb 100644 (file)
@@ -327,19 +327,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
            args->start.tgtdev_name[0] == '\0')
                return -EINVAL;
 
-       /*
-        * Here we commit the transaction to make sure commit_total_bytes
-        * of all the devices are updated.
-        */
-       trans = btrfs_attach_transaction(root);
-       if (!IS_ERR(trans)) {
-               ret = btrfs_commit_transaction(trans, root);
-               if (ret)
-                       return ret;
-       } else if (PTR_ERR(trans) != -ENOENT) {
-               return PTR_ERR(trans);
-       }
-
        /* the disk copy procedure reuses the scrub code */
        mutex_lock(&fs_info->volume_mutex);
        ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid,
@@ -356,6 +343,19 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        if (ret)
                return ret;
 
+       /*
+        * Here we commit the transaction to make sure commit_total_bytes
+        * of all the devices are updated.
+        */
+       trans = btrfs_attach_transaction(root);
+       if (!IS_ERR(trans)) {
+               ret = btrfs_commit_transaction(trans, root);
+               if (ret)
+                       return ret;
+       } else if (PTR_ERR(trans) != -ENOENT) {
+               return PTR_ERR(trans);
+       }
+
        btrfs_dev_replace_lock(dev_replace);
        switch (dev_replace->replace_state) {
        case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
@@ -375,12 +375,8 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        WARN_ON(!tgt_device);
        dev_replace->tgtdev = tgt_device;
 
-       ret = btrfs_kobj_add_device(tgt_device->fs_devices, tgt_device);
-       if (ret)
-               btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret);
-
-       printk_in_rcu(KERN_INFO
-                     "BTRFS: dev_replace from %s (devid %llu) to %s started\n",
+       btrfs_info_in_rcu(root->fs_info,
+                     "dev_replace from %s (devid %llu) to %s started",
                      src_device->missing ? "<missing disk>" :
                        rcu_str_deref(src_device->name),
                      src_device->devid,
@@ -401,6 +397,10 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
        btrfs_dev_replace_unlock(dev_replace);
 
+       ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);
+       if (ret)
+               btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret);
+
        btrfs_wait_ordered_roots(root->fs_info, -1);
 
        /* force writing the updated state information to disk */
@@ -454,8 +454,7 @@ static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info)
 static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info)
 {
        clear_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state);
-       if (waitqueue_active(&fs_info->replace_wait))
-               wake_up(&fs_info->replace_wait);
+       wake_up(&fs_info->replace_wait);
 }
 
 static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
@@ -523,8 +522,8 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                                                                src_device,
                                                                tgt_device);
        } else {
-               printk_in_rcu(KERN_ERR
-                             "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n",
+               btrfs_err_in_rcu(root->fs_info,
+                             "btrfs_scrub_dev(%s, %llu, %s) failed %d",
                              src_device->missing ? "<missing disk>" :
                                rcu_str_deref(src_device->name),
                              src_device->devid,
@@ -540,8 +539,8 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                return scrub_ret;
        }
 
-       printk_in_rcu(KERN_INFO
-                     "BTRFS: dev_replace from %s (devid %llu) to %s finished\n",
+       btrfs_info_in_rcu(root->fs_info,
+                     "dev_replace from %s (devid %llu) to %s finished",
                      src_device->missing ? "<missing disk>" :
                        rcu_str_deref(src_device->name),
                      src_device->devid,
@@ -586,7 +585,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        mutex_unlock(&uuid_mutex);
 
        /* replace the sysfs entry */
-       btrfs_kobj_rm_device(fs_info->fs_devices, src_device);
+       btrfs_sysfs_rm_device_link(fs_info->fs_devices, src_device);
        btrfs_rm_dev_replace_free_srcdev(fs_info, src_device);
 
        /* write back the superblocks */
@@ -809,8 +808,8 @@ static int btrfs_dev_replace_kthread(void *data)
                progress = status_args->status.progress_1000;
                kfree(status_args);
                progress = div_u64(progress, 10);
-               printk_in_rcu(KERN_INFO
-                       "BTRFS: continuing dev_replace from %s (devid %llu) to %s @%u%%\n",
+               btrfs_info_in_rcu(fs_info,
+                       "continuing dev_replace from %s (devid %llu) to %s @%u%%",
                        dev_replace->srcdev->missing ? "<missing disk>" :
                        rcu_str_deref(dev_replace->srcdev->name),
                        dev_replace->srcdev->devid,
index c339d561e59654935378fb8c23593f418aee2c8f..640598c0d0e7585ff125b1a63ed9e74c2c42eaed 100644 (file)
@@ -319,9 +319,9 @@ static int csum_tree_block(struct btrfs_fs_info *fs_info,
                        memcpy(&found, result, csum_size);
 
                        read_extent_buffer(buf, &val, 0, csum_size);
-                       printk_ratelimited(KERN_WARNING
-                               "BTRFS: %s checksum verify failed on %llu wanted %X found %X "
-                               "level %d\n",
+                       btrfs_warn_rl(fs_info,
+                               "%s checksum verify failed on %llu wanted %X found %X "
+                               "level %d",
                                fs_info->sb->s_id, buf->start,
                                val, found, btrfs_header_level(buf));
                        if (result != (char *)&inline_result)
@@ -368,9 +368,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                ret = 0;
                goto out;
        }
-       printk_ratelimited(KERN_ERR
-           "BTRFS (device %s): parent transid verify failed on %llu wanted %llu found %llu\n",
-                       eb->fs_info->sb->s_id, eb->start,
+       btrfs_err_rl(eb->fs_info,
+               "parent transid verify failed on %llu wanted %llu found %llu",
+                       eb->start,
                        parent_transid, btrfs_header_generation(eb));
        ret = 1;
 
@@ -629,15 +629,14 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 
        found_start = btrfs_header_bytenr(eb);
        if (found_start != eb->start) {
-               printk_ratelimited(KERN_ERR "BTRFS (device %s): bad tree block start "
-                              "%llu %llu\n",
-                              eb->fs_info->sb->s_id, found_start, eb->start);
+               btrfs_err_rl(eb->fs_info, "bad tree block start %llu %llu",
+                              found_start, eb->start);
                ret = -EIO;
                goto err;
        }
        if (check_tree_block_fsid(root->fs_info, eb)) {
-               printk_ratelimited(KERN_ERR "BTRFS (device %s): bad fsid on block %llu\n",
-                              eb->fs_info->sb->s_id, eb->start);
+               btrfs_err_rl(eb->fs_info, "bad fsid on block %llu",
+                              eb->start);
                ret = -EIO;
                goto err;
        }
@@ -802,6 +801,9 @@ static void run_one_async_done(struct btrfs_work *work)
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
 
+       /*
+        * atomic_dec_return implies a barrier for waitqueue_active
+        */
        if (atomic_dec_return(&fs_info->nr_async_submits) < limit &&
            waitqueue_active(&fs_info->async_submit_wait))
                wake_up(&fs_info->async_submit_wait);
@@ -1265,6 +1267,7 @@ static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize,
        atomic_set(&root->orphan_inodes, 0);
        atomic_set(&root->refs, 1);
        atomic_set(&root->will_be_snapshoted, 0);
+       atomic_set(&root->qgroup_meta_rsv, 0);
        root->log_transid = 0;
        root->log_transid_committed = -1;
        root->last_log_commit = 0;
@@ -1759,6 +1762,7 @@ static int cleaner_kthread(void *arg)
        int again;
        struct btrfs_trans_handle *trans;
 
+       set_freezable();
        do {
                again = 0;
 
@@ -2348,8 +2352,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
        u64 bytenr = btrfs_super_log_root(disk_super);
 
        if (fs_devices->rw_devices == 0) {
-               printk(KERN_WARNING "BTRFS: log replay required "
-                      "on RO media\n");
+               btrfs_warn(fs_info, "log replay required on RO media");
                return -EIO;
        }
 
@@ -2364,12 +2367,12 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
        log_tree_root->node = read_tree_block(tree_root, bytenr,
                        fs_info->generation + 1);
        if (IS_ERR(log_tree_root->node)) {
-               printk(KERN_ERR "BTRFS: failed to read log tree\n");
+               btrfs_warn(fs_info, "failed to read log tree");
                ret = PTR_ERR(log_tree_root->node);
                kfree(log_tree_root);
                return ret;
        } else if (!extent_buffer_uptodate(log_tree_root->node)) {
-               printk(KERN_ERR "BTRFS: failed to read log tree\n");
+               btrfs_err(fs_info, "failed to read log tree");
                free_extent_buffer(log_tree_root->node);
                kfree(log_tree_root);
                return -EIO;
@@ -2377,7 +2380,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
        /* returns with log_tree_root freed on success */
        ret = btrfs_recover_log_trees(log_tree_root);
        if (ret) {
-               btrfs_error(tree_root->fs_info, ret,
+               btrfs_std_error(tree_root->fs_info, ret,
                            "Failed to recover log tree");
                free_extent_buffer(log_tree_root->node);
                kfree(log_tree_root);
@@ -2653,8 +2656,8 @@ int open_ctree(struct super_block *sb,
         * Read super block and check the signature bytes only
         */
        bh = btrfs_read_dev_super(fs_devices->latest_bdev);
-       if (!bh) {
-               err = -EINVAL;
+       if (IS_ERR(bh)) {
+               err = PTR_ERR(bh);
                goto fail_alloc;
        }
 
@@ -2937,7 +2940,7 @@ retry_root_backup:
                goto fail_fsdev_sysfs;
        }
 
-       ret = btrfs_sysfs_add_one(fs_info);
+       ret = btrfs_sysfs_add_mounted(fs_info);
        if (ret) {
                pr_err("BTRFS: failed to init sysfs interface: %d\n", ret);
                goto fail_fsdev_sysfs;
@@ -3117,7 +3120,7 @@ fail_cleaner:
        filemap_write_and_wait(fs_info->btree_inode->i_mapping);
 
 fail_sysfs:
-       btrfs_sysfs_remove_one(fs_info);
+       btrfs_sysfs_remove_mounted(fs_info);
 
 fail_fsdev_sysfs:
        btrfs_sysfs_remove_fsid(fs_info->fs_devices);
@@ -3179,8 +3182,8 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
                struct btrfs_device *device = (struct btrfs_device *)
                        bh->b_private;
 
-               printk_ratelimited_in_rcu(KERN_WARNING "BTRFS: lost page write due to "
-                                         "I/O error on %s\n",
+               btrfs_warn_rl_in_rcu(device->dev_root->fs_info,
+                               "lost page write due to IO error on %s",
                                          rcu_str_deref(device->name));
                /* note, we dont' set_buffer_write_io_error because we have
                 * our own ways of dealing with the IO errors
@@ -3192,6 +3195,37 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
        put_bh(bh);
 }
 
+int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
+                       struct buffer_head **bh_ret)
+{
+       struct buffer_head *bh;
+       struct btrfs_super_block *super;
+       u64 bytenr;
+
+       bytenr = btrfs_sb_offset(copy_num);
+       if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode))
+               return -EINVAL;
+
+       bh = __bread(bdev, bytenr / 4096, BTRFS_SUPER_INFO_SIZE);
+       /*
+        * If we fail to read from the underlying devices, as of now
+        * the best option we have is to mark it EIO.
+        */
+       if (!bh)
+               return -EIO;
+
+       super = (struct btrfs_super_block *)bh->b_data;
+       if (btrfs_super_bytenr(super) != bytenr ||
+                   btrfs_super_magic(super) != BTRFS_MAGIC) {
+               brelse(bh);
+               return -EINVAL;
+       }
+
+       *bh_ret = bh;
+       return 0;
+}
+
+
 struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
 {
        struct buffer_head *bh;
@@ -3199,7 +3233,7 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
        struct btrfs_super_block *super;
        int i;
        u64 transid = 0;
-       u64 bytenr;
+       int ret = -EINVAL;
 
        /* we would like to check all the supers, but that would make
         * a btrfs mount succeed after a mkfs from a different FS.
@@ -3207,21 +3241,11 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
         * later supers, using BTRFS_SUPER_MIRROR_MAX instead
         */
        for (i = 0; i < 1; i++) {
-               bytenr = btrfs_sb_offset(i);
-               if (bytenr + BTRFS_SUPER_INFO_SIZE >=
-                                       i_size_read(bdev->bd_inode))
-                       break;
-               bh = __bread(bdev, bytenr / 4096,
-                                       BTRFS_SUPER_INFO_SIZE);
-               if (!bh)
+               ret = btrfs_read_dev_one_super(bdev, i, &bh);
+               if (ret)
                        continue;
 
                super = (struct btrfs_super_block *)bh->b_data;
-               if (btrfs_super_bytenr(super) != bytenr ||
-                   btrfs_super_magic(super) != BTRFS_MAGIC) {
-                       brelse(bh);
-                       continue;
-               }
 
                if (!latest || btrfs_super_generation(super) > transid) {
                        brelse(latest);
@@ -3231,6 +3255,10 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
                        brelse(bh);
                }
        }
+
+       if (!latest)
+               return ERR_PTR(ret);
+
        return latest;
 }
 
@@ -3299,8 +3327,9 @@ static int write_dev_supers(struct btrfs_device *device,
                        bh = __getblk(device->bdev, bytenr / 4096,
                                      BTRFS_SUPER_INFO_SIZE);
                        if (!bh) {
-                               printk(KERN_ERR "BTRFS: couldn't get super "
-                                      "buffer head for bytenr %Lu\n", bytenr);
+                               btrfs_err(device->dev_root->fs_info,
+                                   "couldn't get super buffer head for bytenr %llu",
+                                   bytenr);
                                errors++;
                                continue;
                        }
@@ -3449,22 +3478,31 @@ static int barrier_all_devices(struct btrfs_fs_info *info)
 
 int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags)
 {
-       if ((flags & (BTRFS_BLOCK_GROUP_DUP |
-                     BTRFS_BLOCK_GROUP_RAID0 |
-                     BTRFS_AVAIL_ALLOC_BIT_SINGLE)) ||
-           ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0))
-               return 0;
+       int raid_type;
+       int min_tolerated = INT_MAX;
 
-       if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
-                    BTRFS_BLOCK_GROUP_RAID5 |
-                    BTRFS_BLOCK_GROUP_RAID10))
-               return 1;
+       if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 ||
+           (flags & BTRFS_AVAIL_ALLOC_BIT_SINGLE))
+               min_tolerated = min(min_tolerated,
+                                   btrfs_raid_array[BTRFS_RAID_SINGLE].
+                                   tolerated_failures);
 
-       if (flags & BTRFS_BLOCK_GROUP_RAID6)
-               return 2;
+       for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) {
+               if (raid_type == BTRFS_RAID_SINGLE)
+                       continue;
+               if (!(flags & btrfs_raid_group[raid_type]))
+                       continue;
+               min_tolerated = min(min_tolerated,
+                                   btrfs_raid_array[raid_type].
+                                   tolerated_failures);
+       }
 
-       pr_warn("BTRFS: unknown raid type: %llu\n", flags);
-       return 0;
+       if (min_tolerated == INT_MAX) {
+               pr_warn("BTRFS: unknown raid flag: %llu\n", flags);
+               min_tolerated = 0;
+       }
+
+       return min_tolerated;
 }
 
 int btrfs_calc_num_tolerated_disk_barrier_failures(
@@ -3548,7 +3586,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                if (ret) {
                        mutex_unlock(
                                &root->fs_info->fs_devices->device_list_mutex);
-                       btrfs_error(root->fs_info, ret,
+                       btrfs_std_error(root->fs_info, ret,
                                    "errors while submitting device barriers.");
                        return ret;
                }
@@ -3588,7 +3626,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
                /* FUA is masked off if unsupported and can't be the reason */
-               btrfs_error(root->fs_info, -EIO,
+               btrfs_std_error(root->fs_info, -EIO,
                            "%d errors while writing supers", total_errors);
                return -EIO;
        }
@@ -3606,7 +3644,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
        }
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
        if (total_errors > max_errors) {
-               btrfs_error(root->fs_info, -EIO,
+               btrfs_std_error(root->fs_info, -EIO,
                            "%d errors while writing supers", total_errors);
                return -EIO;
        }
@@ -3792,7 +3830,7 @@ void close_ctree(struct btrfs_root *root)
                       percpu_counter_sum(&fs_info->delalloc_bytes));
        }
 
-       btrfs_sysfs_remove_one(fs_info);
+       btrfs_sysfs_remove_mounted(fs_info);
        btrfs_sysfs_remove_fsid(fs_info->fs_devices);
 
        btrfs_free_fs_roots(fs_info);
@@ -4290,25 +4328,6 @@ again:
        return 0;
 }
 
-static void btrfs_free_pending_ordered(struct btrfs_transaction *cur_trans,
-                                      struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_ordered_extent *ordered;
-
-       spin_lock(&fs_info->trans_lock);
-       while (!list_empty(&cur_trans->pending_ordered)) {
-               ordered = list_first_entry(&cur_trans->pending_ordered,
-                                          struct btrfs_ordered_extent,
-                                          trans_list);
-               list_del_init(&ordered->trans_list);
-               spin_unlock(&fs_info->trans_lock);
-
-               btrfs_put_ordered_extent(ordered);
-               spin_lock(&fs_info->trans_lock);
-       }
-       spin_unlock(&fs_info->trans_lock);
-}
-
 void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                   struct btrfs_root *root)
 {
@@ -4320,7 +4339,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
        cur_trans->state = TRANS_STATE_UNBLOCKED;
        wake_up(&root->fs_info->transaction_wait);
 
-       btrfs_free_pending_ordered(cur_trans, root->fs_info);
        btrfs_destroy_delayed_inodes(root);
        btrfs_assert_delayed_root_empty(root);
 
index bdfb479ea85955112305d0c30a17af9c7647daed..adeb31830b9cc1d49d145fdaa4f476c23dc81aa7 100644 (file)
@@ -60,6 +60,8 @@ void close_ctree(struct btrfs_root *root);
 int write_ctree_super(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root, int max_mirrors);
 struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
+int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
+                       struct buffer_head **bh_ret);
 int btrfs_commit_super(struct btrfs_root *root);
 struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info,
                                            u64 bytenr);
index 601d7d45d164a7e91477748a900bbef8cf67d0b0..99a8e57da8a11fbbdcbc0d833a687d79629200cc 100644 (file)
@@ -95,8 +95,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 parent, u64 root_objectid,
                                     u64 flags, struct btrfs_disk_key *key,
-                                    int level, struct btrfs_key *ins,
-                                    int no_quota);
+                                    int level, struct btrfs_key *ins);
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 flags,
                          int force);
@@ -332,6 +331,27 @@ static void put_caching_control(struct btrfs_caching_control *ctl)
                kfree(ctl);
 }
 
+#ifdef CONFIG_BTRFS_DEBUG
+static void fragment_free_space(struct btrfs_root *root,
+                               struct btrfs_block_group_cache *block_group)
+{
+       u64 start = block_group->key.objectid;
+       u64 len = block_group->key.offset;
+       u64 chunk = block_group->flags & BTRFS_BLOCK_GROUP_METADATA ?
+               root->nodesize : root->sectorsize;
+       u64 step = chunk << 1;
+
+       while (len > chunk) {
+               btrfs_remove_free_space(block_group, start, chunk);
+               start += step;
+               if (len < step)
+                       len = 0;
+               else
+                       len -= step;
+       }
+}
+#endif
+
 /*
  * this is only called by cache_block_group, since we could have freed extents
  * we need to check the pinned_extents for any extents that can't be used yet
@@ -388,6 +408,7 @@ static noinline void caching_thread(struct btrfs_work *work)
        u64 last = 0;
        u32 nritems;
        int ret = -ENOMEM;
+       bool wakeup = true;
 
        caching_ctl = container_of(work, struct btrfs_caching_control, work);
        block_group = caching_ctl->block_group;
@@ -400,6 +421,15 @@ static noinline void caching_thread(struct btrfs_work *work)
 
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
 
+#ifdef CONFIG_BTRFS_DEBUG
+       /*
+        * If we're fragmenting we don't want to make anybody think we can
+        * allocate from this block group until we've had a chance to fragment
+        * the free space.
+        */
+       if (btrfs_should_fragment_free_space(extent_root, block_group))
+               wakeup = false;
+#endif
        /*
         * We don't want to deadlock with somebody trying to allocate a new
         * extent for the extent root while also trying to search the extent
@@ -441,7 +471,8 @@ next:
 
                        if (need_resched() ||
                            rwsem_is_contended(&fs_info->commit_root_sem)) {
-                               caching_ctl->progress = last;
+                               if (wakeup)
+                                       caching_ctl->progress = last;
                                btrfs_release_path(path);
                                up_read(&fs_info->commit_root_sem);
                                mutex_unlock(&caching_ctl->mutex);
@@ -464,7 +495,8 @@ next:
                        key.offset = 0;
                        key.type = BTRFS_EXTENT_ITEM_KEY;
 
-                       caching_ctl->progress = last;
+                       if (wakeup)
+                               caching_ctl->progress = last;
                        btrfs_release_path(path);
                        goto next;
                }
@@ -491,7 +523,8 @@ next:
 
                        if (total_found > (1024 * 1024 * 2)) {
                                total_found = 0;
-                               wake_up(&caching_ctl->wait);
+                               if (wakeup)
+                                       wake_up(&caching_ctl->wait);
                        }
                }
                path->slots[0]++;
@@ -501,13 +534,27 @@ next:
        total_found += add_new_free_space(block_group, fs_info, last,
                                          block_group->key.objectid +
                                          block_group->key.offset);
-       caching_ctl->progress = (u64)-1;
-
        spin_lock(&block_group->lock);
        block_group->caching_ctl = NULL;
        block_group->cached = BTRFS_CACHE_FINISHED;
        spin_unlock(&block_group->lock);
 
+#ifdef CONFIG_BTRFS_DEBUG
+       if (btrfs_should_fragment_free_space(extent_root, block_group)) {
+               u64 bytes_used;
+
+               spin_lock(&block_group->space_info->lock);
+               spin_lock(&block_group->lock);
+               bytes_used = block_group->key.offset -
+                       btrfs_block_group_used(&block_group->item);
+               block_group->space_info->bytes_used += bytes_used >> 1;
+               spin_unlock(&block_group->lock);
+               spin_unlock(&block_group->space_info->lock);
+               fragment_free_space(extent_root, block_group);
+       }
+#endif
+
+       caching_ctl->progress = (u64)-1;
 err:
        btrfs_free_path(path);
        up_read(&fs_info->commit_root_sem);
@@ -607,6 +654,22 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
                        }
                }
                spin_unlock(&cache->lock);
+#ifdef CONFIG_BTRFS_DEBUG
+               if (ret == 1 &&
+                   btrfs_should_fragment_free_space(fs_info->extent_root,
+                                                    cache)) {
+                       u64 bytes_used;
+
+                       spin_lock(&cache->space_info->lock);
+                       spin_lock(&cache->lock);
+                       bytes_used = cache->key.offset -
+                               btrfs_block_group_used(&cache->item);
+                       cache->space_info->bytes_used += bytes_used >> 1;
+                       spin_unlock(&cache->lock);
+                       spin_unlock(&cache->space_info->lock);
+                       fragment_free_space(fs_info->extent_root, cache);
+               }
+#endif
                mutex_unlock(&caching_ctl->mutex);
 
                wake_up(&caching_ctl->wait);
@@ -2009,8 +2072,7 @@ 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,
-                        int no_quota)
+                        u64 root_objectid, u64 owner, u64 offset)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -2022,12 +2084,12 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
                                        num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_ADD_DELAYED_REF, NULL, no_quota);
+                                       BTRFS_ADD_DELAYED_REF, NULL);
        } else {
                ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
-                                       num_bytes,
-                                       parent, root_objectid, owner, offset,
-                                       BTRFS_ADD_DELAYED_REF, NULL, no_quota);
+                                       num_bytes, parent, root_objectid,
+                                       owner, offset, 0,
+                                       BTRFS_ADD_DELAYED_REF, NULL);
        }
        return ret;
 }
@@ -2048,15 +2110,11 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        u64 num_bytes = node->num_bytes;
        u64 refs;
        int ret;
-       int no_quota = node->no_quota;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       if (!is_fstree(root_objectid) || !root->fs_info->quota_enabled)
-               no_quota = 1;
-
        path->reada = 1;
        path->leave_spinning = 1;
        /* this will setup the path even if it fails to insert the back ref */
@@ -2291,8 +2349,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
                                                parent, ref_root,
                                                extent_op->flags_to_set,
                                                &extent_op->key,
-                                               ref->level, &ins,
-                                               node->no_quota);
+                                               ref->level, &ins);
        } else if (node->action == BTRFS_ADD_DELAYED_REF) {
                ret = __btrfs_inc_extent_ref(trans, root, node,
                                             parent, ref_root,
@@ -2345,6 +2402,11 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                                                      node->num_bytes);
                        }
                }
+
+               /* Also free its reserved qgroup space */
+               btrfs_qgroup_free_delayed_ref(root->fs_info,
+                                             head->qgroup_ref_root,
+                                             head->qgroup_reserved);
                return ret;
        }
 
@@ -2433,7 +2495,21 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                        }
                }
 
+               /*
+                * We need to try and merge add/drops of the same ref since we
+                * can run into issues with relocate dropping the implicit ref
+                * and then it being added back again before the drop can
+                * finish.  If we merged anything we need to re-loop so we can
+                * get a good ref.
+                * Or we can get node references of the same type that weren't
+                * merged when created due to bumps in the tree mod seq, and
+                * we need to merge them to prevent adding an inline extent
+                * backref before dropping it (triggering a BUG_ON at
+                * insert_inline_extent_backref()).
+                */
                spin_lock(&locked_ref->lock);
+               btrfs_merge_delayed_refs(trans, fs_info, delayed_refs,
+                                        locked_ref);
 
                /*
                 * locked_ref is the head node, so we have to go one
@@ -3109,7 +3185,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, int);
+                           u64, u64, u64, u64, u64, u64);
 
 
        if (btrfs_test_is_dummy_root(root))
@@ -3150,15 +3226,14 @@ 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, 1);
+                                          key.offset);
                        if (ret)
                                goto fail;
                } else {
                        bytenr = btrfs_node_blockptr(buf, i);
                        num_bytes = root->nodesize;
                        ret = process_func(trans, root, bytenr, num_bytes,
-                                          parent, ref_root, level - 1, 0,
-                                          1);
+                                          parent, ref_root, level - 1, 0);
                        if (ret)
                                goto fail;
                }
@@ -3338,6 +3413,15 @@ again:
        }
        spin_unlock(&block_group->lock);
 
+       /*
+        * We hit an ENOSPC when setting up the cache in this transaction, just
+        * skip doing the setup, we've already cleared the cache so we're safe.
+        */
+       if (test_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags)) {
+               ret = -ENOSPC;
+               goto out_put;
+       }
+
        /*
         * Try to preallocate enough space based on how big the block group is.
         * Keep in mind this has to include any pinned space which could end up
@@ -3351,16 +3435,26 @@ again:
        num_pages *= 16;
        num_pages *= PAGE_CACHE_SIZE;
 
-       ret = btrfs_check_data_free_space(inode, num_pages, num_pages);
+       ret = btrfs_check_data_free_space(inode, 0, num_pages);
        if (ret)
                goto out_put;
 
        ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
                                              num_pages, num_pages,
                                              &alloc_hint);
+       /*
+        * Our cache requires contiguous chunks so that we don't modify a bunch
+        * of metadata or split extents when writing the cache out, which means
+        * we can enospc if we are heavily fragmented in addition to just normal
+        * out of space conditions.  So if we hit this just skip setting up any
+        * other block groups for this transaction, maybe we'll unpin enough
+        * space the next time around.
+        */
        if (!ret)
                dcs = BTRFS_DC_SETUP;
-       btrfs_free_reserved_data_space(inode, num_pages);
+       else if (ret == -ENOSPC)
+               set_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags);
+       btrfs_free_reserved_data_space(inode, 0, num_pages);
 
 out_put:
        iput(inode);
@@ -3746,6 +3840,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->bytes_readonly = 0;
        found->bytes_may_use = 0;
        found->full = 0;
+       found->max_extent_size = 0;
        found->force_alloc = CHUNK_ALLOC_NO_FORCE;
        found->chunk_alloc = 0;
        found->flush = 0;
@@ -3822,7 +3917,8 @@ static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
        u64 num_devices = root->fs_info->fs_devices->rw_devices;
        u64 target;
-       u64 tmp;
+       u64 raid_type;
+       u64 allowed = 0;
 
        /*
         * see if restripe for this chunk_type is in progress, if so
@@ -3840,31 +3936,26 @@ static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
        spin_unlock(&root->fs_info->balance_lock);
 
        /* First, mask out the RAID levels which aren't possible */
-       if (num_devices == 1)
-               flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0 |
-                          BTRFS_BLOCK_GROUP_RAID5);
-       if (num_devices < 3)
-               flags &= ~BTRFS_BLOCK_GROUP_RAID6;
-       if (num_devices < 4)
-               flags &= ~BTRFS_BLOCK_GROUP_RAID10;
-
-       tmp = flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID0 |
-                      BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID5 |
-                      BTRFS_BLOCK_GROUP_RAID6 | BTRFS_BLOCK_GROUP_RAID10);
-       flags &= ~tmp;
-
-       if (tmp & BTRFS_BLOCK_GROUP_RAID6)
-               tmp = BTRFS_BLOCK_GROUP_RAID6;
-       else if (tmp & BTRFS_BLOCK_GROUP_RAID5)
-               tmp = BTRFS_BLOCK_GROUP_RAID5;
-       else if (tmp & BTRFS_BLOCK_GROUP_RAID10)
-               tmp = BTRFS_BLOCK_GROUP_RAID10;
-       else if (tmp & BTRFS_BLOCK_GROUP_RAID1)
-               tmp = BTRFS_BLOCK_GROUP_RAID1;
-       else if (tmp & BTRFS_BLOCK_GROUP_RAID0)
-               tmp = BTRFS_BLOCK_GROUP_RAID0;
-
-       return extended_to_chunk(flags | tmp);
+       for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) {
+               if (num_devices >= btrfs_raid_array[raid_type].devs_min)
+                       allowed |= btrfs_raid_group[raid_type];
+       }
+       allowed &= flags;
+
+       if (allowed & BTRFS_BLOCK_GROUP_RAID6)
+               allowed = BTRFS_BLOCK_GROUP_RAID6;
+       else if (allowed & BTRFS_BLOCK_GROUP_RAID5)
+               allowed = BTRFS_BLOCK_GROUP_RAID5;
+       else if (allowed & BTRFS_BLOCK_GROUP_RAID10)
+               allowed = BTRFS_BLOCK_GROUP_RAID10;
+       else if (allowed & BTRFS_BLOCK_GROUP_RAID1)
+               allowed = BTRFS_BLOCK_GROUP_RAID1;
+       else if (allowed & BTRFS_BLOCK_GROUP_RAID0)
+               allowed = BTRFS_BLOCK_GROUP_RAID0;
+
+       flags &= ~BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       return extended_to_chunk(flags | allowed);
 }
 
 static u64 get_alloc_profile(struct btrfs_root *root, u64 orig_flags)
@@ -3903,11 +3994,7 @@ u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data)
        return ret;
 }
 
-/*
- * This will check the space that the inode allocates from to make sure we have
- * enough space for bytes.
- */
-int btrfs_check_data_free_space(struct inode *inode, u64 bytes, u64 write_bytes)
+int btrfs_alloc_data_chunk_ondemand(struct inode *inode, u64 bytes)
 {
        struct btrfs_space_info *data_sinfo;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -4006,7 +4093,8 @@ commit_trans:
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
                        if (have_pinned_space >= 0 ||
-                           trans->transaction->have_free_bgs ||
+                           test_bit(BTRFS_TRANS_HAVE_FREE_BGS,
+                                    &trans->transaction->flags) ||
                            need_commit > 0) {
                                ret = btrfs_commit_transaction(trans, root);
                                if (ret)
@@ -4028,38 +4116,86 @@ commit_trans:
                                              data_sinfo->flags, bytes, 1);
                return -ENOSPC;
        }
-       ret = btrfs_qgroup_reserve(root, write_bytes);
-       if (ret)
-               goto out;
        data_sinfo->bytes_may_use += bytes;
        trace_btrfs_space_reservation(root->fs_info, "space_info",
                                      data_sinfo->flags, bytes, 1);
-out:
        spin_unlock(&data_sinfo->lock);
 
        return ret;
 }
 
 /*
- * Called if we need to clear a data reservation for this inode.
+ * New check_data_free_space() with ability for precious data reservation
+ * Will replace old btrfs_check_data_free_space(), but for patch split,
+ * add a new function first and then replace it.
+ */
+int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       /* align the range */
+       len = round_up(start + len, root->sectorsize) -
+             round_down(start, root->sectorsize);
+       start = round_down(start, root->sectorsize);
+
+       ret = btrfs_alloc_data_chunk_ondemand(inode, len);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Use new btrfs_qgroup_reserve_data to reserve precious data space
+        *
+        * TODO: Find a good method to avoid reserve data space for NOCOW
+        * range, but don't impact performance on quota disable case.
+        */
+       ret = btrfs_qgroup_reserve_data(inode, start, len);
+       return ret;
+}
+
+/*
+ * Called if we need to clear a data reservation for this inode
+ * Normally in a error case.
+ *
+ * This one will *NOT* use accurate qgroup reserved space API, just for case
+ * which we can't sleep and is sure it won't affect qgroup reserved space.
+ * Like clear_bit_hook().
  */
-void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
+void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
+                                           u64 len)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_space_info *data_sinfo;
 
-       /* make sure bytes are sectorsize aligned */
-       bytes = ALIGN(bytes, root->sectorsize);
+       /* Make sure the range is aligned to sectorsize */
+       len = round_up(start + len, root->sectorsize) -
+             round_down(start, root->sectorsize);
+       start = round_down(start, root->sectorsize);
 
        data_sinfo = root->fs_info->data_sinfo;
        spin_lock(&data_sinfo->lock);
-       WARN_ON(data_sinfo->bytes_may_use < bytes);
-       data_sinfo->bytes_may_use -= bytes;
+       if (WARN_ON(data_sinfo->bytes_may_use < len))
+               data_sinfo->bytes_may_use = 0;
+       else
+               data_sinfo->bytes_may_use -= len;
        trace_btrfs_space_reservation(root->fs_info, "space_info",
-                                     data_sinfo->flags, bytes, 0);
+                                     data_sinfo->flags, len, 0);
        spin_unlock(&data_sinfo->lock);
 }
 
+/*
+ * Called if we need to clear a data reservation for this inode
+ * Normally in a error case.
+ *
+ * This one will handle the per-indoe data rsv map for accurate reserved
+ * space framework.
+ */
+void btrfs_free_reserved_data_space(struct inode *inode, u64 start, u64 len)
+{
+       btrfs_free_reserved_data_space_noquota(inode, start, len);
+       btrfs_qgroup_free_data(inode, start, len);
+}
+
 static void force_metadata_allocation(struct btrfs_fs_info *info)
 {
        struct list_head *head = &info->space_info;
@@ -4891,13 +5027,9 @@ static struct btrfs_block_rsv *get_block_rsv(
 {
        struct btrfs_block_rsv *block_rsv = NULL;
 
-       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
-               block_rsv = trans->block_rsv;
-
-       if (root == root->fs_info->csum_root && trans->adding_csums)
-               block_rsv = trans->block_rsv;
-
-       if (root == root->fs_info->uuid_root)
+       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
+           (root == root->fs_info->csum_root && trans->adding_csums) ||
+            (root == root->fs_info->uuid_root))
                block_rsv = trans->block_rsv;
 
        if (!block_rsv)
@@ -5340,7 +5472,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
        if (root->fs_info->quota_enabled) {
                /* One for parent inode, two for dir entries */
                num_bytes = 3 * root->nodesize;
-               ret = btrfs_qgroup_reserve(root, num_bytes);
+               ret = btrfs_qgroup_reserve_meta(root, num_bytes);
                if (ret)
                        return ret;
        } else {
@@ -5358,10 +5490,8 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
        if (ret == -ENOSPC && use_global_rsv)
                ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes);
 
-       if (ret) {
-               if (*qgroup_reserved)
-                       btrfs_qgroup_free(root, *qgroup_reserved);
-       }
+       if (ret && *qgroup_reserved)
+               btrfs_qgroup_free_meta(root, *qgroup_reserved);
 
        return ret;
 }
@@ -5522,15 +5652,15 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        spin_unlock(&BTRFS_I(inode)->lock);
 
        if (root->fs_info->quota_enabled) {
-               ret = btrfs_qgroup_reserve(root, nr_extents * root->nodesize);
+               ret = btrfs_qgroup_reserve_meta(root,
+                               nr_extents * root->nodesize);
                if (ret)
                        goto out_fail;
        }
 
        ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
        if (unlikely(ret)) {
-               if (root->fs_info->quota_enabled)
-                       btrfs_qgroup_free(root, nr_extents * root->nodesize);
+               btrfs_qgroup_free_meta(root, nr_extents * root->nodesize);
                goto out_fail;
        }
 
@@ -5653,41 +5783,48 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 }
 
 /**
- * btrfs_delalloc_reserve_space - reserve data and metadata space for delalloc
+ * btrfs_delalloc_reserve_space - reserve data and metadata space for
+ * delalloc
  * @inode: inode we're writing to
- * @num_bytes: the number of bytes we want to allocate
+ * @start: start range we are writing to
+ * @len: how long the range we are writing to
+ *
+ * TODO: This function will finally replace old btrfs_delalloc_reserve_space()
  *
  * This will do the following things
  *
- * o reserve space in the data space info for num_bytes
- * o reserve space in the metadata space info based on number of outstanding
+ * o reserve space in data space info for num bytes
+ *   and reserve precious corresponding qgroup space
+ *   (Done in check_data_free_space)
+ *
+ * o reserve space for metadata space, based on the number of outstanding
  *   extents and how much csums will be needed
- * o add to the inodes ->delalloc_bytes
+ *   also reserve metadata space in a per root over-reserve method.
+ * o add to the inodes->delalloc_bytes
  * o add it to the fs_info's delalloc inodes list.
+ *   (Above 3 all done in delalloc_reserve_metadata)
  *
- * This will return 0 for success and -ENOSPC if there is no space left.
+ * Return 0 for success
+ * Return <0 for error(-ENOSPC or -EQUOT)
  */
-int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
+int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len)
 {
        int ret;
 
-       ret = btrfs_check_data_free_space(inode, num_bytes, num_bytes);
-       if (ret)
-               return ret;
-
-       ret = btrfs_delalloc_reserve_metadata(inode, num_bytes);
-       if (ret) {
-               btrfs_free_reserved_data_space(inode, num_bytes);
+       ret = btrfs_check_data_free_space(inode, start, len);
+       if (ret < 0)
                return ret;
-       }
-
-       return 0;
+       ret = btrfs_delalloc_reserve_metadata(inode, len);
+       if (ret < 0)
+               btrfs_free_reserved_data_space(inode, start, len);
+       return ret;
 }
 
 /**
  * btrfs_delalloc_release_space - release data and metadata space for delalloc
  * @inode: inode we're releasing space for
- * @num_bytes: the number of bytes we want to free up
+ * @start: start position of the space already reserved
+ * @len: the len of the space already reserved
  *
  * This must be matched with a call to btrfs_delalloc_reserve_space.  This is
  * called in the case that we don't need the metadata AND data reservations
@@ -5696,11 +5833,12 @@ int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
  * This function will release the metadata space that was not used and will
  * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
  * list if there are no delalloc bytes left.
+ * Also it will handle the qgroup reserved space.
  */
-void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes)
+void btrfs_delalloc_release_space(struct inode *inode, u64 start, u64 len)
 {
-       btrfs_delalloc_release_metadata(inode, num_bytes);
-       btrfs_free_reserved_data_space(inode, num_bytes);
+       btrfs_delalloc_release_metadata(inode, len);
+       btrfs_free_reserved_data_space(inode, start, len);
 }
 
 static int update_block_group(struct btrfs_trans_handle *trans,
@@ -6065,6 +6203,34 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
        update_global_block_rsv(fs_info);
 }
 
+/*
+ * Returns the free cluster for the given space info and sets empty_cluster to
+ * what it should be based on the mount options.
+ */
+static struct btrfs_free_cluster *
+fetch_cluster_info(struct btrfs_root *root, struct btrfs_space_info *space_info,
+                  u64 *empty_cluster)
+{
+       struct btrfs_free_cluster *ret = NULL;
+       bool ssd = btrfs_test_opt(root, SSD);
+
+       *empty_cluster = 0;
+       if (btrfs_mixed_space_info(space_info))
+               return ret;
+
+       if (ssd)
+               *empty_cluster = 2 * 1024 * 1024;
+       if (space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
+               ret = &root->fs_info->meta_alloc_cluster;
+               if (!ssd)
+                       *empty_cluster = 64 * 1024;
+       } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && ssd) {
+               ret = &root->fs_info->data_alloc_cluster;
+       }
+
+       return ret;
+}
+
 static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end,
                              const bool return_free_space)
 {
@@ -6072,7 +6238,10 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end,
        struct btrfs_block_group_cache *cache = NULL;
        struct btrfs_space_info *space_info;
        struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       struct btrfs_free_cluster *cluster = NULL;
        u64 len;
+       u64 total_unpinned = 0;
+       u64 empty_cluster = 0;
        bool readonly;
 
        while (start <= end) {
@@ -6081,8 +6250,14 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end,
                    start >= cache->key.objectid + cache->key.offset) {
                        if (cache)
                                btrfs_put_block_group(cache);
+                       total_unpinned = 0;
                        cache = btrfs_lookup_block_group(fs_info, start);
                        BUG_ON(!cache); /* Logic error */
+
+                       cluster = fetch_cluster_info(root,
+                                                    cache->space_info,
+                                                    &empty_cluster);
+                       empty_cluster <<= 1;
                }
 
                len = cache->key.objectid + cache->key.offset - start;
@@ -6095,12 +6270,27 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end,
                }
 
                start += len;
+               total_unpinned += len;
                space_info = cache->space_info;
 
+               /*
+                * If this space cluster has been marked as fragmented and we've
+                * unpinned enough in this block group to potentially allow a
+                * cluster to be created inside of it go ahead and clear the
+                * fragmented check.
+                */
+               if (cluster && cluster->fragmented &&
+                   total_unpinned > empty_cluster) {
+                       spin_lock(&cluster->lock);
+                       cluster->fragmented = 0;
+                       spin_unlock(&cluster->lock);
+               }
+
                spin_lock(&space_info->lock);
                spin_lock(&cache->lock);
                cache->pinned -= len;
                space_info->bytes_pinned -= len;
+               space_info->max_extent_size = 0;
                percpu_counter_add(&space_info->total_bytes_pinned, -len);
                if (cache->ro) {
                        space_info->bytes_readonly += len;
@@ -6233,7 +6423,6 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
        int extent_slot = 0;
        int found_extent = 0;
        int num_to_del = 1;
-       int no_quota = node->no_quota;
        u32 item_size;
        u64 refs;
        u64 bytenr = node->bytenr;
@@ -6242,9 +6431,6 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
        bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
                                                 SKINNY_METADATA);
 
-       if (!info->quota_enabled || !is_fstree(root_objectid))
-               no_quota = 1;
-
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -6570,7 +6756,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                                        buf->start, buf->len,
                                        parent, root->root_key.objectid,
                                        btrfs_header_level(buf),
-                                       BTRFS_DROP_DELAYED_REF, NULL, 0);
+                                       BTRFS_DROP_DELAYED_REF, NULL);
                BUG_ON(ret); /* -ENOMEM */
        }
 
@@ -6618,7 +6804,7 @@ out:
 /* Can return -ENOMEM */
 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 no_quota)
+                     u64 owner, u64 offset)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -6641,13 +6827,13 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
                                        num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_DROP_DELAYED_REF, NULL, no_quota);
+                                       BTRFS_DROP_DELAYED_REF, NULL);
        } else {
                ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
                                                num_bytes,
                                                parent, root_objectid, owner,
-                                               offset, BTRFS_DROP_DELAYED_REF,
-                                               NULL, no_quota);
+                                               offset, 0,
+                                               BTRFS_DROP_DELAYED_REF, NULL);
        }
        return ret;
 }
@@ -6833,7 +7019,7 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        struct btrfs_block_group_cache *block_group = NULL;
        u64 search_start = 0;
        u64 max_extent_size = 0;
-       int empty_cluster = 2 * 1024 * 1024;
+       u64 empty_cluster = 0;
        struct btrfs_space_info *space_info;
        int loop = 0;
        int index = __get_raid_index(flags);
@@ -6843,6 +7029,8 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        bool failed_alloc = false;
        bool use_cluster = true;
        bool have_caching_bg = false;
+       bool orig_have_caching_bg = false;
+       bool full_search = false;
 
        WARN_ON(num_bytes < root->sectorsize);
        ins->type = BTRFS_EXTENT_ITEM_KEY;
@@ -6858,36 +7046,47 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        }
 
        /*
-        * If the space info is for both data and metadata it means we have a
-        * small filesystem and we can't use the clustering stuff.
+        * If our free space is heavily fragmented we may not be able to make
+        * big contiguous allocations, so instead of doing the expensive search
+        * for free space, simply return ENOSPC with our max_extent_size so we
+        * can go ahead and search for a more manageable chunk.
+        *
+        * If our max_extent_size is large enough for our allocation simply
+        * disable clustering since we will likely not be able to find enough
+        * space to create a cluster and induce latency trying.
         */
-       if (btrfs_mixed_space_info(space_info))
-               use_cluster = false;
-
-       if (flags & BTRFS_BLOCK_GROUP_METADATA && use_cluster) {
-               last_ptr = &root->fs_info->meta_alloc_cluster;
-               if (!btrfs_test_opt(root, SSD))
-                       empty_cluster = 64 * 1024;
-       }
-
-       if ((flags & BTRFS_BLOCK_GROUP_DATA) && use_cluster &&
-           btrfs_test_opt(root, SSD)) {
-               last_ptr = &root->fs_info->data_alloc_cluster;
+       if (unlikely(space_info->max_extent_size)) {
+               spin_lock(&space_info->lock);
+               if (space_info->max_extent_size &&
+                   num_bytes > space_info->max_extent_size) {
+                       ins->offset = space_info->max_extent_size;
+                       spin_unlock(&space_info->lock);
+                       return -ENOSPC;
+               } else if (space_info->max_extent_size) {
+                       use_cluster = false;
+               }
+               spin_unlock(&space_info->lock);
        }
 
+       last_ptr = fetch_cluster_info(orig_root, space_info, &empty_cluster);
        if (last_ptr) {
                spin_lock(&last_ptr->lock);
                if (last_ptr->block_group)
                        hint_byte = last_ptr->window_start;
+               if (last_ptr->fragmented) {
+                       /*
+                        * We still set window_start so we can keep track of the
+                        * last place we found an allocation to try and save
+                        * some time.
+                        */
+                       hint_byte = last_ptr->window_start;
+                       use_cluster = false;
+               }
                spin_unlock(&last_ptr->lock);
        }
 
        search_start = max(search_start, first_logical_byte(root, 0));
        search_start = max(search_start, hint_byte);
-
-       if (!last_ptr)
-               empty_cluster = 0;
-
        if (search_start == hint_byte) {
                block_group = btrfs_lookup_block_group(root->fs_info,
                                                       search_start);
@@ -6922,6 +7121,8 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        }
 search:
        have_caching_bg = false;
+       if (index == 0 || index == __get_raid_index(flags))
+               full_search = true;
        down_read(&space_info->groups_sem);
        list_for_each_entry(block_group, &space_info->block_groups[index],
                            list) {
@@ -6955,6 +7156,7 @@ search:
 have_block_group:
                cached = block_group_cache_done(block_group);
                if (unlikely(!cached)) {
+                       have_caching_bg = true;
                        ret = cache_block_group(block_group, 0);
                        BUG_ON(ret < 0);
                        ret = 0;
@@ -6969,7 +7171,7 @@ have_block_group:
                 * Ok we want to try and use the cluster allocator, so
                 * lets look there
                 */
-               if (last_ptr) {
+               if (last_ptr && use_cluster) {
                        struct btrfs_block_group_cache *used_block_group;
                        unsigned long aligned_cluster;
                        /*
@@ -7095,6 +7297,16 @@ refill_cluster:
                }
 
 unclustered_alloc:
+               /*
+                * We are doing an unclustered alloc, set the fragmented flag so
+                * we don't bother trying to setup a cluster again until we get
+                * more space.
+                */
+               if (unlikely(last_ptr)) {
+                       spin_lock(&last_ptr->lock);
+                       last_ptr->fragmented = 1;
+                       spin_unlock(&last_ptr->lock);
+               }
                spin_lock(&block_group->free_space_ctl->tree_lock);
                if (cached &&
                    block_group->free_space_ctl->free_space <
@@ -7127,8 +7339,6 @@ unclustered_alloc:
                        failed_alloc = true;
                        goto have_block_group;
                } else if (!offset) {
-                       if (!cached)
-                               have_caching_bg = true;
                        goto loop;
                }
 checks:
@@ -7169,6 +7379,10 @@ loop:
        }
        up_read(&space_info->groups_sem);
 
+       if ((loop == LOOP_CACHING_NOWAIT) && have_caching_bg
+               && !orig_have_caching_bg)
+               orig_have_caching_bg = true;
+
        if (!ins->objectid && loop >= LOOP_CACHING_WAIT && have_caching_bg)
                goto search;
 
@@ -7185,7 +7399,20 @@ loop:
         */
        if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE) {
                index = 0;
-               loop++;
+               if (loop == LOOP_CACHING_NOWAIT) {
+                       /*
+                        * We want to skip the LOOP_CACHING_WAIT step if we
+                        * don't have any unached bgs and we've alrelady done a
+                        * full search through.
+                        */
+                       if (orig_have_caching_bg || !full_search)
+                               loop = LOOP_CACHING_WAIT;
+                       else
+                               loop = LOOP_ALLOC_CHUNK;
+               } else {
+                       loop++;
+               }
+
                if (loop == LOOP_ALLOC_CHUNK) {
                        struct btrfs_trans_handle *trans;
                        int exist = 0;
@@ -7203,6 +7430,15 @@ loop:
 
                        ret = do_chunk_alloc(trans, root, flags,
                                             CHUNK_ALLOC_FORCE);
+
+                       /*
+                        * If we can't allocate a new chunk we've already looped
+                        * through at least once, move on to the NO_EMPTY_SIZE
+                        * case.
+                        */
+                       if (ret == -ENOSPC)
+                               loop = LOOP_NO_EMPTY_SIZE;
+
                        /*
                         * Do not bail out on ENOSPC since we
                         * can do more things.
@@ -7219,6 +7455,15 @@ loop:
                }
 
                if (loop == LOOP_NO_EMPTY_SIZE) {
+                       /*
+                        * Don't loop again if we already have no empty_size and
+                        * no empty_cluster.
+                        */
+                       if (empty_size == 0 &&
+                           empty_cluster == 0) {
+                               ret = -ENOSPC;
+                               goto out;
+                       }
                        empty_size = 0;
                        empty_cluster = 0;
                }
@@ -7227,11 +7472,20 @@ loop:
        } else if (!ins->objectid) {
                ret = -ENOSPC;
        } else if (ins->objectid) {
+               if (!use_cluster && last_ptr) {
+                       spin_lock(&last_ptr->lock);
+                       last_ptr->window_start = ins->objectid;
+                       spin_unlock(&last_ptr->lock);
+               }
                ret = 0;
        }
 out:
-       if (ret == -ENOSPC)
+       if (ret == -ENOSPC) {
+               spin_lock(&space_info->lock);
+               space_info->max_extent_size = max_extent_size;
+               spin_unlock(&space_info->lock);
                ins->offset = max_extent_size;
+       }
        return ret;
 }
 
@@ -7280,7 +7534,7 @@ int btrfs_reserve_extent(struct btrfs_root *root,
                         u64 empty_size, u64 hint_byte,
                         struct btrfs_key *ins, int is_data, int delalloc)
 {
-       bool final_tried = false;
+       bool final_tried = num_bytes == min_alloc_size;
        u64 flags;
        int ret;
 
@@ -7429,8 +7683,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 parent, u64 root_objectid,
                                     u64 flags, struct btrfs_disk_key *key,
-                                    int level, struct btrfs_key *ins,
-                                    int no_quota)
+                                    int level, struct btrfs_key *ins)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -7511,7 +7764,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 root_objectid, u64 owner,
-                                    u64 offset, struct btrfs_key *ins)
+                                    u64 offset, u64 ram_bytes,
+                                    struct btrfs_key *ins)
 {
        int ret;
 
@@ -7520,7 +7774,8 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        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);
+                                        ram_bytes, BTRFS_ADD_DELAYED_EXTENT,
+                                        NULL);
        return ret;
 }
 
@@ -7734,7 +7989,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                                                 ins.objectid, ins.offset,
                                                 parent, root_objectid, level,
                                                 BTRFS_ADD_DELAYED_EXTENT,
-                                                extent_op, 0);
+                                                extent_op);
                if (ret)
                        goto out_free_delayed;
        }
@@ -8275,14 +8530,15 @@ skip:
                        ret = account_shared_subtree(trans, root, next,
                                                     generation, level - 1);
                        if (ret) {
-                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                               btrfs_err_rl(root->fs_info,
+                                       "Error "
                                        "%d accounting shared subtree. Quota "
-                                       "is out of sync, rescan required.\n",
-                                       root->fs_info->sb->s_id, ret);
+                                       "is out of sync, rescan required.",
+                                       ret);
                        }
                }
                ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
-                               root->root_key.objectid, level - 1, 0, 0);
+                               root->root_key.objectid, level - 1, 0);
                BUG_ON(ret); /* -ENOMEM */
        }
        btrfs_tree_unlock(next);
@@ -8367,10 +8623,11 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                        BUG_ON(ret); /* -ENOMEM */
                        ret = account_leaf_items(trans, root, eb);
                        if (ret) {
-                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                               btrfs_err_rl(root->fs_info,
+                                       "error "
                                        "%d accounting leaf items. Quota "
-                                       "is out of sync, rescan required.\n",
-                                       root->fs_info->sb->s_id, ret);
+                                       "is out of sync, rescan required.",
+                                       ret);
                        }
                }
                /* make block locked assertion in clean_tree_block happy */
@@ -8692,7 +8949,7 @@ out:
        if (!for_reloc && root_dropped == false)
                btrfs_add_dead_root(root);
        if (err && err != -EAGAIN)
-               btrfs_std_error(root->fs_info, err);
+               btrfs_std_error(root->fs_info, err, NULL);
        return err;
 }
 
@@ -8880,7 +9137,7 @@ again:
         * back off and let this transaction commit
         */
        mutex_lock(&root->fs_info->ro_block_group_mutex);
-       if (trans->transaction->dirty_bg_run) {
+       if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) {
                u64 transid = trans->transid;
 
                mutex_unlock(&root->fs_info->ro_block_group_mutex);
@@ -9630,6 +9887,14 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        free_excluded_extents(root, cache);
 
+#ifdef CONFIG_BTRFS_DEBUG
+       if (btrfs_should_fragment_free_space(root, cache)) {
+               u64 new_bytes_used = size - bytes_used;
+
+               bytes_used += new_bytes_used >> 1;
+               fragment_free_space(root, cache);
+       }
+#endif
        /*
         * Call to ensure the corresponding space_info object is created and
         * assigned to our block group, but don't update its counters just yet.
@@ -10370,8 +10635,7 @@ void btrfs_end_write_no_snapshoting(struct btrfs_root *root)
 {
        percpu_counter_dec(&root->subv_writers->counter);
        /*
-        * Make sure counter is updated before we wake up
-        * waiters.
+        * Make sure counter is updated before we wake up waiters.
         */
        smp_mb();
        if (waitqueue_active(&root->subv_writers->wait))
index 032abfbebe76e6e4ba41e25d7c9326079ed71f68..9abe18763a7fb001632246fd712a64fdffcc0225 100644 (file)
@@ -96,8 +96,8 @@ static inline void __btrfs_debug_check_extent_io_range(const char *caller,
        inode = tree->mapping->host;
        isize = i_size_read(inode);
        if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) {
-               printk_ratelimited(KERN_DEBUG
-                   "BTRFS: %s: ino %llu isize %llu odd range [%llu,%llu]\n",
+               btrfs_debug_rl(BTRFS_I(inode)->root->fs_info,
+                   "%s: ino %llu isize %llu odd range [%llu,%llu]",
                                caller, btrfs_ino(inode), isize, start, end);
        }
 }
@@ -131,6 +131,25 @@ struct extent_page_data {
        unsigned int sync_io:1;
 };
 
+static void add_extent_changeset(struct extent_state *state, unsigned bits,
+                                struct extent_changeset *changeset,
+                                int set)
+{
+       int ret;
+
+       if (!changeset)
+               return;
+       if (set && (state->state & bits) == bits)
+               return;
+       if (!set && (state->state & bits) == 0)
+               return;
+       changeset->bytes_changed += state->end - state->start + 1;
+       ret = ulist_add(changeset->range_changed, state->start, state->end,
+                       GFP_ATOMIC);
+       /* ENOMEM */
+       BUG_ON(ret < 0);
+}
+
 static noinline void flush_write_bio(void *data);
 static inline struct btrfs_fs_info *
 tree_fs_info(struct extent_io_tree *tree)
@@ -410,7 +429,8 @@ static void clear_state_cb(struct extent_io_tree *tree,
 }
 
 static void set_state_bits(struct extent_io_tree *tree,
-                          struct extent_state *state, unsigned *bits);
+                          struct extent_state *state, unsigned *bits,
+                          struct extent_changeset *changeset);
 
 /*
  * insert an extent_state struct into the tree.  'bits' are set on the
@@ -426,7 +446,7 @@ static int insert_state(struct extent_io_tree *tree,
                        struct extent_state *state, u64 start, u64 end,
                        struct rb_node ***p,
                        struct rb_node **parent,
-                       unsigned *bits)
+                       unsigned *bits, struct extent_changeset *changeset)
 {
        struct rb_node *node;
 
@@ -436,7 +456,7 @@ static int insert_state(struct extent_io_tree *tree,
        state->start = start;
        state->end = end;
 
-       set_state_bits(tree, state, bits);
+       set_state_bits(tree, state, bits, changeset);
 
        node = tree_insert(&tree->state, NULL, end, &state->rb_node, p, parent);
        if (node) {
@@ -511,7 +531,8 @@ static struct extent_state *next_state(struct extent_state *state)
  */
 static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
                                            struct extent_state *state,
-                                           unsigned *bits, int wake)
+                                           unsigned *bits, int wake,
+                                           struct extent_changeset *changeset)
 {
        struct extent_state *next;
        unsigned bits_to_clear = *bits & ~EXTENT_CTLBITS;
@@ -522,6 +543,7 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
                tree->dirty_bytes -= range;
        }
        clear_state_cb(tree, state, bits);
+       add_extent_changeset(state, bits_to_clear, changeset, 0);
        state->state &= ~bits_to_clear;
        if (wake)
                wake_up(&state->wq);
@@ -569,10 +591,10 @@ static void extent_io_tree_panic(struct extent_io_tree *tree, int err)
  *
  * This takes the tree lock, and returns 0 on success and < 0 on error.
  */
-int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
-                    unsigned bits, int wake, int delete,
-                    struct extent_state **cached_state,
-                    gfp_t mask)
+static int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
+                             unsigned bits, int wake, int delete,
+                             struct extent_state **cached_state,
+                             gfp_t mask, struct extent_changeset *changeset)
 {
        struct extent_state *state;
        struct extent_state *cached;
@@ -671,7 +693,8 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       state = clear_state_bit(tree, state, &bits, wake);
+                       state = clear_state_bit(tree, state, &bits, wake,
+                                               changeset);
                        goto next;
                }
                goto search_again;
@@ -692,13 +715,13 @@ hit_next:
                if (wake)
                        wake_up(&state->wq);
 
-               clear_state_bit(tree, prealloc, &bits, wake);
+               clear_state_bit(tree, prealloc, &bits, wake, changeset);
 
                prealloc = NULL;
                goto out;
        }
 
-       state = clear_state_bit(tree, state, &bits, wake);
+       state = clear_state_bit(tree, state, &bits, wake, changeset);
 next:
        if (last_end == (u64)-1)
                goto out;
@@ -789,7 +812,7 @@ out:
 
 static void set_state_bits(struct extent_io_tree *tree,
                           struct extent_state *state,
-                          unsigned *bits)
+                          unsigned *bits, struct extent_changeset *changeset)
 {
        unsigned bits_to_set = *bits & ~EXTENT_CTLBITS;
 
@@ -798,6 +821,7 @@ static void set_state_bits(struct extent_io_tree *tree,
                u64 range = state->end - state->start + 1;
                tree->dirty_bytes += range;
        }
+       add_extent_changeset(state, bits_to_set, changeset, 1);
        state->state |= bits_to_set;
 }
 
@@ -835,7 +859,7 @@ static int __must_check
 __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                 unsigned bits, unsigned exclusive_bits,
                 u64 *failed_start, struct extent_state **cached_state,
-                gfp_t mask)
+                gfp_t mask, struct extent_changeset *changeset)
 {
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
@@ -873,7 +897,7 @@ again:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = insert_state(tree, prealloc, start, end,
-                                  &p, &parent, &bits);
+                                  &p, &parent, &bits, changeset);
                if (err)
                        extent_io_tree_panic(tree, err);
 
@@ -899,7 +923,7 @@ hit_next:
                        goto out;
                }
 
-               set_state_bits(tree, state, &bits);
+               set_state_bits(tree, state, &bits, changeset);
                cache_state(state, cached_state);
                merge_state(tree, state);
                if (last_end == (u64)-1)
@@ -945,7 +969,7 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       set_state_bits(tree, state, &bits);
+                       set_state_bits(tree, state, &bits, changeset);
                        cache_state(state, cached_state);
                        merge_state(tree, state);
                        if (last_end == (u64)-1)
@@ -980,7 +1004,7 @@ hit_next:
                 * the later extent.
                 */
                err = insert_state(tree, prealloc, start, this_end,
-                                  NULL, NULL, &bits);
+                                  NULL, NULL, &bits, changeset);
                if (err)
                        extent_io_tree_panic(tree, err);
 
@@ -1008,7 +1032,7 @@ hit_next:
                if (err)
                        extent_io_tree_panic(tree, err);
 
-               set_state_bits(tree, prealloc, &bits);
+               set_state_bits(tree, prealloc, &bits, changeset);
                cache_state(prealloc, cached_state);
                merge_state(tree, prealloc);
                prealloc = NULL;
@@ -1038,7 +1062,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                   struct extent_state **cached_state, gfp_t mask)
 {
        return __set_extent_bit(tree, start, end, bits, 0, failed_start,
-                               cached_state, mask);
+                               cached_state, mask, NULL);
 }
 
 
@@ -1111,7 +1135,7 @@ again:
                        goto out;
                }
                err = insert_state(tree, prealloc, start, end,
-                                  &p, &parent, &bits);
+                                  &p, &parent, &bits, NULL);
                if (err)
                        extent_io_tree_panic(tree, err);
                cache_state(prealloc, cached_state);
@@ -1130,9 +1154,9 @@ hit_next:
         * Just lock what we found and keep going
         */
        if (state->start == start && state->end <= end) {
-               set_state_bits(tree, state, &bits);
+               set_state_bits(tree, state, &bits, NULL);
                cache_state(state, cached_state);
-               state = clear_state_bit(tree, state, &clear_bits, 0);
+               state = clear_state_bit(tree, state, &clear_bits, 0, NULL);
                if (last_end == (u64)-1)
                        goto out;
                start = last_end + 1;
@@ -1171,9 +1195,10 @@ hit_next:
                if (err)
                        goto out;
                if (state->end <= end) {
-                       set_state_bits(tree, state, &bits);
+                       set_state_bits(tree, state, &bits, NULL);
                        cache_state(state, cached_state);
-                       state = clear_state_bit(tree, state, &clear_bits, 0);
+                       state = clear_state_bit(tree, state, &clear_bits, 0,
+                                               NULL);
                        if (last_end == (u64)-1)
                                goto out;
                        start = last_end + 1;
@@ -1208,7 +1233,7 @@ hit_next:
                 * the later extent.
                 */
                err = insert_state(tree, prealloc, start, this_end,
-                                  NULL, NULL, &bits);
+                                  NULL, NULL, &bits, NULL);
                if (err)
                        extent_io_tree_panic(tree, err);
                cache_state(prealloc, cached_state);
@@ -1233,9 +1258,9 @@ hit_next:
                if (err)
                        extent_io_tree_panic(tree, err);
 
-               set_state_bits(tree, prealloc, &bits);
+               set_state_bits(tree, prealloc, &bits, NULL);
                cache_state(prealloc, cached_state);
-               clear_state_bit(tree, prealloc, &clear_bits, 0);
+               clear_state_bit(tree, prealloc, &clear_bits, 0, NULL);
                prealloc = NULL;
                goto out;
        }
@@ -1274,6 +1299,30 @@ int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                              NULL, mask);
 }
 
+int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
+                          unsigned bits, gfp_t mask,
+                          struct extent_changeset *changeset)
+{
+       /*
+        * We don't support EXTENT_LOCKED yet, as current changeset will
+        * record any bits changed, so for EXTENT_LOCKED case, it will
+        * either fail with -EEXIST or changeset will record the whole
+        * range.
+        */
+       BUG_ON(bits & EXTENT_LOCKED);
+
+       return __set_extent_bit(tree, start, end, bits, 0, NULL, NULL, mask,
+                               changeset);
+}
+
+int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
+                    unsigned bits, int wake, int delete,
+                    struct extent_state **cached, gfp_t mask)
+{
+       return __clear_extent_bit(tree, start, end, bits, wake, delete,
+                                 cached, mask, NULL);
+}
+
 int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                      unsigned bits, gfp_t mask)
 {
@@ -1285,6 +1334,20 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
        return clear_extent_bit(tree, start, end, bits, wake, 0, NULL, mask);
 }
 
+int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
+                            unsigned bits, gfp_t mask,
+                            struct extent_changeset *changeset)
+{
+       /*
+        * Don't support EXTENT_LOCKED case, same reason as
+        * set_record_extent_bits().
+        */
+       BUG_ON(bits & EXTENT_LOCKED);
+
+       return __clear_extent_bit(tree, start, end, bits, 0, 0, NULL, mask,
+                                 changeset);
+}
+
 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
                        struct extent_state **cached_state, gfp_t mask)
 {
@@ -1343,7 +1406,7 @@ int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
        while (1) {
                err = __set_extent_bit(tree, start, end, EXTENT_LOCKED | bits,
                                       EXTENT_LOCKED, &failed_start,
-                                      cached_state, GFP_NOFS);
+                                      cached_state, GFP_NOFS, NULL);
                if (err == -EEXIST) {
                        wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
                        start = failed_start;
@@ -1365,7 +1428,7 @@ int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
        u64 failed_start;
 
        err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, EXTENT_LOCKED,
-                              &failed_start, NULL, GFP_NOFS);
+                              &failed_start, NULL, GFP_NOFS, NULL);
        if (err == -EEXIST) {
                if (failed_start > start)
                        clear_extent_bit(tree, start, failed_start - 1,
@@ -2078,8 +2141,8 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
                return -EIO;
        }
 
-       printk_ratelimited_in_rcu(KERN_INFO
-                                 "BTRFS: read error corrected: ino %llu off %llu (dev %s sector %llu)\n",
+       btrfs_info_rl_in_rcu(fs_info,
+               "read error corrected: ino %llu off %llu (dev %s sector %llu)",
                                  btrfs_ino(inode), start,
                                  rcu_str_deref(dev->name), sector);
        bio_put(bio);
@@ -3070,8 +3133,12 @@ static int __do_readpage(struct extent_io_tree *tree,
 
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
                                            &cached, GFP_NOFS);
-                       unlock_extent_cached(tree, cur, cur + iosize - 1,
-                                            &cached, GFP_NOFS);
+                       if (parent_locked)
+                               free_extent_state(cached);
+                       else
+                               unlock_extent_cached(tree, cur,
+                                                    cur + iosize - 1,
+                                                    &cached, GFP_NOFS);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -5566,13 +5633,15 @@ void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
        unsigned long src_i;
 
        if (src_offset + len > dst->len) {
-               printk(KERN_ERR "BTRFS: memmove bogus src_offset %lu move "
-                      "len %lu dst len %lu\n", src_offset, len, dst->len);
+               btrfs_err(dst->fs_info,
+                       "memmove bogus src_offset %lu move "
+                      "len %lu dst len %lu", src_offset, len, dst->len);
                BUG_ON(1);
        }
        if (dst_offset + len > dst->len) {
-               printk(KERN_ERR "BTRFS: memmove bogus dst_offset %lu move "
-                      "len %lu dst len %lu\n", dst_offset, len, dst->len);
+               btrfs_err(dst->fs_info,
+                       "memmove bogus dst_offset %lu move "
+                      "len %lu dst len %lu", dst_offset, len, dst->len);
                BUG_ON(1);
        }
 
@@ -5612,13 +5681,13 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
        unsigned long src_i;
 
        if (src_offset + len > dst->len) {
-               printk(KERN_ERR "BTRFS: memmove bogus src_offset %lu move "
-                      "len %lu len %lu\n", src_offset, len, dst->len);
+               btrfs_err(dst->fs_info, "memmove bogus src_offset %lu move "
+                      "len %lu len %lu", src_offset, len, dst->len);
                BUG_ON(1);
        }
        if (dst_offset + len > dst->len) {
-               printk(KERN_ERR "BTRFS: memmove bogus dst_offset %lu move "
-                      "len %lu len %lu\n", dst_offset, len, dst->len);
+               btrfs_err(dst->fs_info, "memmove bogus dst_offset %lu move "
+                      "len %lu len %lu", dst_offset, len, dst->len);
                BUG_ON(1);
        }
        if (dst_offset < src_offset) {
index c668f36898d3a4c2dd2e0e18456dd2cfa6c55747..f4c1ae11855f0b613894ea44026faf143021b613 100644 (file)
@@ -2,6 +2,7 @@
 #define __EXTENTIO__
 
 #include <linux/rbtree.h>
+#include "ulist.h"
 
 /* bits for the extent state */
 #define EXTENT_DIRTY           (1U << 0)
@@ -18,6 +19,7 @@
 #define EXTENT_NEED_WAIT       (1U << 13)
 #define EXTENT_DAMAGED         (1U << 14)
 #define EXTENT_NORESERVE       (1U << 15)
+#define EXTENT_QGROUP_RESERVED (1U << 16)
 #define EXTENT_IOBITS          (EXTENT_LOCKED | EXTENT_WRITEBACK)
 #define EXTENT_CTLBITS         (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC)
 
@@ -161,6 +163,17 @@ struct extent_buffer {
 #endif
 };
 
+/*
+ * Structure to record how many bytes and which ranges are set/cleared
+ */
+struct extent_changeset {
+       /* How many bytes are set/cleared in this operation */
+       u64 bytes_changed;
+
+       /* Changed ranges */
+       struct ulist *range_changed;
+};
+
 static inline void extent_set_compress_type(unsigned long *bio_flags,
                                            int compress_type)
 {
@@ -210,11 +223,17 @@ int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
                   struct extent_state *cached_state);
 int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                      unsigned bits, gfp_t mask);
+int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
+                            unsigned bits, gfp_t mask,
+                            struct extent_changeset *changeset);
 int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                     unsigned bits, int wake, int delete,
                     struct extent_state **cached, gfp_t mask);
 int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
                    unsigned bits, gfp_t mask);
+int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
+                          unsigned bits, gfp_t mask,
+                          struct extent_changeset *changeset);
 int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                   unsigned bits, u64 *failed_start,
                   struct extent_state **cached_state, gfp_t mask);
index 8c6f247ba81d4e84c6a7d3d00d0348c974c1b049..6bd5ce9d75f0ab8eaca5a2f808bfaf5a66132742 100644 (file)
@@ -847,7 +847,7 @@ next_slot:
                                                disk_bytenr, num_bytes, 0,
                                                root->root_key.objectid,
                                                new_key.objectid,
-                                               start - extent_offset, 1);
+                                               start - extent_offset);
                                BUG_ON(ret); /* -ENOMEM */
                        }
                        key.offset = start;
@@ -925,7 +925,7 @@ delete_extent_item:
                                                disk_bytenr, num_bytes, 0,
                                                root->root_key.objectid,
                                                key.objectid, key.offset -
-                                               extent_offset, 0);
+                                               extent_offset);
                                BUG_ON(ret); /* -ENOMEM */
                                inode_sub_bytes(inode,
                                                extent_end - key.offset);
@@ -1204,7 +1204,7 @@ again:
 
                ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
                                           root->root_key.objectid,
-                                          ino, orig_offset, 1);
+                                          ino, orig_offset);
                BUG_ON(ret); /* -ENOMEM */
 
                if (split == start) {
@@ -1231,7 +1231,7 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       ino, orig_offset, 0);
+                                       ino, orig_offset);
                BUG_ON(ret); /* -ENOMEM */
        }
        other_start = 0;
@@ -1248,7 +1248,7 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       ino, orig_offset, 0);
+                                       ino, orig_offset);
                BUG_ON(ret); /* -ENOMEM */
        }
        if (del_nr == 0) {
@@ -1469,7 +1469,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        u64 release_bytes = 0;
        u64 lockstart;
        u64 lockend;
-       unsigned long first_index;
        size_t num_written = 0;
        int nrptrs;
        int ret = 0;
@@ -1485,8 +1484,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        if (!pages)
                return -ENOMEM;
 
-       first_index = pos >> PAGE_CACHE_SHIFT;
-
        while (iov_iter_count(i) > 0) {
                size_t offset = pos & (PAGE_CACHE_SIZE - 1);
                size_t write_bytes = min(iov_iter_count(i),
@@ -1510,12 +1507,17 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                }
 
                reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
-               ret = btrfs_check_data_free_space(inode, reserve_bytes, write_bytes);
-               if (ret == -ENOSPC &&
-                   (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
-                                             BTRFS_INODE_PREALLOC))) {
+
+               if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
+                                            BTRFS_INODE_PREALLOC)) {
                        ret = check_can_nocow(inode, pos, &write_bytes);
+                       if (ret < 0)
+                               break;
                        if (ret > 0) {
+                               /*
+                                * For nodata cow case, no need to reserve
+                                * data space.
+                                */
                                only_release_metadata = true;
                                /*
                                 * our prealloc extent may be smaller than
@@ -1524,20 +1526,19 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                                num_pages = DIV_ROUND_UP(write_bytes + offset,
                                                         PAGE_CACHE_SIZE);
                                reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
-                               ret = 0;
-                       } else {
-                               ret = -ENOSPC;
+                               goto reserve_metadata;
                        }
                }
-
-               if (ret)
+               ret = btrfs_check_data_free_space(inode, pos, write_bytes);
+               if (ret < 0)
                        break;
 
+reserve_metadata:
                ret = btrfs_delalloc_reserve_metadata(inode, reserve_bytes);
                if (ret) {
                        if (!only_release_metadata)
-                               btrfs_free_reserved_data_space(inode,
-                                                              reserve_bytes);
+                               btrfs_free_reserved_data_space(inode, pos,
+                                                              write_bytes);
                        else
                                btrfs_end_write_no_snapshoting(root);
                        break;
@@ -1603,12 +1604,17 @@ again:
                                BTRFS_I(inode)->outstanding_extents++;
                                spin_unlock(&BTRFS_I(inode)->lock);
                        }
-                       if (only_release_metadata)
+                       if (only_release_metadata) {
                                btrfs_delalloc_release_metadata(inode,
                                                                release_bytes);
-                       else
-                               btrfs_delalloc_release_space(inode,
+                       } else {
+                               u64 __pos;
+
+                               __pos = round_down(pos, root->sectorsize) +
+                                       (dirty_pages << PAGE_CACHE_SHIFT);
+                               btrfs_delalloc_release_space(inode, __pos,
                                                             release_bytes);
+                       }
                }
 
                release_bytes = dirty_pages << PAGE_CACHE_SHIFT;
@@ -1660,7 +1666,7 @@ again:
                        btrfs_end_write_no_snapshoting(root);
                        btrfs_delalloc_release_metadata(inode, release_bytes);
                } else {
-                       btrfs_delalloc_release_space(inode, release_bytes);
+                       btrfs_delalloc_release_space(inode, pos, release_bytes);
                }
        }
 
@@ -2266,7 +2272,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        u64 drop_end;
        int ret = 0;
        int err = 0;
-       int rsv_count;
+       unsigned int rsv_count;
        bool same_page;
        bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
        u64 ino_size;
@@ -2487,6 +2493,19 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        }
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
+       /*
+        * If we are using the NO_HOLES feature we might have had already an
+        * hole that overlaps a part of the region [lockstart, lockend] and
+        * ends at (or beyond) lockend. Since we have no file extent items to
+        * represent holes, drop_end can be less than lockend and so we must
+        * make sure we have an extent map representing the existing hole (the
+        * call to __btrfs_drop_extents() might have dropped the existing extent
+        * map representing the existing hole), otherwise the fast fsync path
+        * will not record the existence of the hole region
+        * [existing_hole_start, lockend].
+        */
+       if (drop_end <= lockend)
+               drop_end = lockend + 1;
        /*
         * Don't insert file hole extent item if it's for a range beyond eof
         * (because it's useless) or if it represents a 0 bytes range (when
@@ -2541,17 +2560,61 @@ out_only_mutex:
        return err;
 }
 
+/* Helper structure to record which range is already reserved */
+struct falloc_range {
+       struct list_head list;
+       u64 start;
+       u64 len;
+};
+
+/*
+ * Helper function to add falloc range
+ *
+ * Caller should have locked the larger range of extent containing
+ * [start, len)
+ */
+static int add_falloc_range(struct list_head *head, u64 start, u64 len)
+{
+       struct falloc_range *prev = NULL;
+       struct falloc_range *range = NULL;
+
+       if (list_empty(head))
+               goto insert;
+
+       /*
+        * As fallocate iterate by bytenr order, we only need to check
+        * the last range.
+        */
+       prev = list_entry(head->prev, struct falloc_range, list);
+       if (prev->start + prev->len == start) {
+               prev->len += len;
+               return 0;
+       }
+insert:
+       range = kmalloc(sizeof(*range), GFP_NOFS);
+       if (!range)
+               return -ENOMEM;
+       range->start = start;
+       range->len = len;
+       list_add_tail(&range->list, head);
+       return 0;
+}
+
 static long btrfs_fallocate(struct file *file, int mode,
                            loff_t offset, loff_t len)
 {
        struct inode *inode = file_inode(file);
        struct extent_state *cached_state = NULL;
+       struct falloc_range *range;
+       struct falloc_range *tmp;
+       struct list_head reserve_list;
        u64 cur_offset;
        u64 last_byte;
        u64 alloc_start;
        u64 alloc_end;
        u64 alloc_hint = 0;
        u64 locked_end;
+       u64 actual_end = 0;
        struct extent_map *em;
        int blocksize = BTRFS_I(inode)->root->sectorsize;
        int ret;
@@ -2567,11 +2630,12 @@ static long btrfs_fallocate(struct file *file, int mode,
                return btrfs_punch_hole(inode, offset, len);
 
        /*
-        * Make sure we have enough space before we do the
-        * allocation.
+        * Only trigger disk allocation, don't trigger qgroup reserve
+        *
+        * For qgroup space, it will be checked later.
         */
-       ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start, alloc_end - alloc_start);
-       if (ret)
+       ret = btrfs_alloc_data_chunk_ondemand(inode, alloc_end - alloc_start);
+       if (ret < 0)
                return ret;
 
        mutex_lock(&inode->i_mutex);
@@ -2579,6 +2643,13 @@ static long btrfs_fallocate(struct file *file, int mode,
        if (ret)
                goto out;
 
+       /*
+        * TODO: Move these two operations after we have checked
+        * accurate reserved space, or fallocate can still fail but
+        * with page truncated or size expanded.
+        *
+        * But that's a minor problem and won't do much harm BTW.
+        */
        if (alloc_start > inode->i_size) {
                ret = btrfs_cont_expand(inode, i_size_read(inode),
                                        alloc_start);
@@ -2637,10 +2708,10 @@ static long btrfs_fallocate(struct file *file, int mode,
                }
        }
 
+       /* First, check if we exceed the qgroup limit */
+       INIT_LIST_HEAD(&reserve_list);
        cur_offset = alloc_start;
        while (1) {
-               u64 actual_end;
-
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
                if (IS_ERR_OR_NULL(em)) {
@@ -2653,57 +2724,82 @@ static long btrfs_fallocate(struct file *file, int mode,
                last_byte = min(extent_map_end(em), alloc_end);
                actual_end = min_t(u64, extent_map_end(em), offset + len);
                last_byte = ALIGN(last_byte, blocksize);
-
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
-                       ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
-                                                       last_byte - cur_offset,
-                                                       1 << inode->i_blkbits,
-                                                       offset + len,
-                                                       &alloc_hint);
-               } else if (actual_end > inode->i_size &&
-                          !(mode & FALLOC_FL_KEEP_SIZE)) {
-                       struct btrfs_trans_handle *trans;
-                       struct btrfs_root *root = BTRFS_I(inode)->root;
-
-                       /*
-                        * We didn't need to allocate any more space, but we
-                        * still extended the size of the file so we need to
-                        * update i_size and the inode item.
-                        */
-                       trans = btrfs_start_transaction(root, 1);
-                       if (IS_ERR(trans)) {
-                               ret = PTR_ERR(trans);
-                       } else {
-                               inode->i_ctime = CURRENT_TIME;
-                               i_size_write(inode, actual_end);
-                               btrfs_ordered_update_i_size(inode, actual_end,
-                                                           NULL);
-                               ret = btrfs_update_inode(trans, root, inode);
-                               if (ret)
-                                       btrfs_end_transaction(trans, root);
-                               else
-                                       ret = btrfs_end_transaction(trans,
-                                                                   root);
+                       ret = add_falloc_range(&reserve_list, cur_offset,
+                                              last_byte - cur_offset);
+                       if (ret < 0) {
+                               free_extent_map(em);
+                               break;
                        }
+                       ret = btrfs_qgroup_reserve_data(inode, cur_offset,
+                                       last_byte - cur_offset);
+                       if (ret < 0)
+                               break;
                }
                free_extent_map(em);
-               if (ret < 0)
-                       break;
-
                cur_offset = last_byte;
-               if (cur_offset >= alloc_end) {
-                       ret = 0;
+               if (cur_offset >= alloc_end)
                        break;
+       }
+
+       /*
+        * If ret is still 0, means we're OK to fallocate.
+        * Or just cleanup the list and exit.
+        */
+       list_for_each_entry_safe(range, tmp, &reserve_list, list) {
+               if (!ret)
+                       ret = btrfs_prealloc_file_range(inode, mode,
+                                       range->start,
+                                       range->len, 1 << inode->i_blkbits,
+                                       offset + len, &alloc_hint);
+               list_del(&range->list);
+               kfree(range);
+       }
+       if (ret < 0)
+               goto out_unlock;
+
+       if (actual_end > inode->i_size &&
+           !(mode & FALLOC_FL_KEEP_SIZE)) {
+               struct btrfs_trans_handle *trans;
+               struct btrfs_root *root = BTRFS_I(inode)->root;
+
+               /*
+                * We didn't need to allocate any more space, but we
+                * still extended the size of the file so we need to
+                * update i_size and the inode item.
+                */
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+               } else {
+                       inode->i_ctime = CURRENT_TIME;
+                       i_size_write(inode, actual_end);
+                       btrfs_ordered_update_i_size(inode, actual_end, NULL);
+                       ret = btrfs_update_inode(trans, root, inode);
+                       if (ret)
+                               btrfs_end_transaction(trans, root);
+                       else
+                               ret = btrfs_end_transaction(trans, root);
                }
        }
+out_unlock:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
                             &cached_state, GFP_NOFS);
 out:
+       /*
+        * As we waited the extent range, the data_rsv_map must be empty
+        * in the range, as written data range will be released from it.
+        * And for prealloacted extent, it will also be released when
+        * its metadata is written.
+        * So this is completely used as cleanup.
+        */
+       btrfs_qgroup_free_data(inode, alloc_start, alloc_end - alloc_start);
        mutex_unlock(&inode->i_mutex);
        /* Let go of our reservation. */
-       btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
+       btrfs_free_reserved_data_space(inode, alloc_start,
+                                      alloc_end - alloc_start);
        return ret;
 }
 
index ed05da1b977e59f6ca54ecfe95be81e85bc631ba..85a1f8621b51f09f0893abae9ffab90382efdcfc 100644 (file)
@@ -450,9 +450,9 @@ static int io_ctl_check_generation(struct btrfs_io_ctl *io_ctl, u64 generation)
 
        gen = io_ctl->cur;
        if (le64_to_cpu(*gen) != generation) {
-               printk_ratelimited(KERN_ERR "BTRFS: space cache generation "
-                                  "(%Lu) does not match inode (%Lu)\n", *gen,
-                                  generation);
+               btrfs_err_rl(io_ctl->root->fs_info,
+                       "space cache generation (%llu) does not match inode (%llu)",
+                               *gen, generation);
                io_ctl_unmap_page(io_ctl);
                return -EIO;
        }
@@ -506,8 +506,8 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
                              PAGE_CACHE_SIZE - offset);
        btrfs_csum_final(crc, (char *)&crc);
        if (val != crc) {
-               printk_ratelimited(KERN_ERR "BTRFS: csum mismatch on free "
-                                  "space cache\n");
+               btrfs_err_rl(io_ctl->root->fs_info,
+                       "csum mismatch on free space cache");
                io_ctl_unmap_page(io_ctl);
                return -EIO;
        }
@@ -1215,7 +1215,7 @@ out:
  * @offset - the offset for the key we'll insert
  *
  * This function writes out a free space cache struct to disk for quick recovery
- * on mount.  This will return 0 if it was successfull in writing the cache out,
+ * on mount.  This will return 0 if it was successful in writing the cache out,
  * or an errno if it was not.
  */
 static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
@@ -1730,7 +1730,7 @@ static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl,
  */
 static int search_bitmap(struct btrfs_free_space_ctl *ctl,
                         struct btrfs_free_space *bitmap_info, u64 *offset,
-                        u64 *bytes)
+                        u64 *bytes, bool for_alloc)
 {
        unsigned long found_bits = 0;
        unsigned long max_bits = 0;
@@ -1738,11 +1738,26 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl,
        unsigned long next_zero;
        unsigned long extent_bits;
 
+       /*
+        * Skip searching the bitmap if we don't have a contiguous section that
+        * is large enough for this allocation.
+        */
+       if (for_alloc &&
+           bitmap_info->max_extent_size &&
+           bitmap_info->max_extent_size < *bytes) {
+               *bytes = bitmap_info->max_extent_size;
+               return -1;
+       }
+
        i = offset_to_bit(bitmap_info->offset, ctl->unit,
                          max_t(u64, *offset, bitmap_info->offset));
        bits = bytes_to_bits(*bytes, ctl->unit);
 
        for_each_set_bit_from(i, bitmap_info->bitmap, BITS_PER_BITMAP) {
+               if (for_alloc && bits == 1) {
+                       found_bits = 1;
+                       break;
+               }
                next_zero = find_next_zero_bit(bitmap_info->bitmap,
                                               BITS_PER_BITMAP, i);
                extent_bits = next_zero - i;
@@ -1762,6 +1777,7 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl,
        }
 
        *bytes = (u64)(max_bits) * ctl->unit;
+       bitmap_info->max_extent_size = *bytes;
        return -1;
 }
 
@@ -1813,7 +1829,7 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes,
                if (entry->bitmap) {
                        u64 size = *bytes;
 
-                       ret = search_bitmap(ctl, entry, &tmp, &size);
+                       ret = search_bitmap(ctl, entry, &tmp, &size, true);
                        if (!ret) {
                                *offset = tmp;
                                *bytes = size;
@@ -1874,7 +1890,8 @@ again:
        search_start = *offset;
        search_bytes = ctl->unit;
        search_bytes = min(search_bytes, end - search_start + 1);
-       ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
+       ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes,
+                           false);
        if (ret < 0 || search_start != *offset)
                return -EINVAL;
 
@@ -1919,7 +1936,7 @@ again:
                search_start = *offset;
                search_bytes = ctl->unit;
                ret = search_bitmap(ctl, bitmap_info, &search_start,
-                                   &search_bytes);
+                                   &search_bytes, false);
                if (ret < 0 || search_start != *offset)
                        return -EAGAIN;
 
@@ -1943,6 +1960,12 @@ static u64 add_bytes_to_bitmap(struct btrfs_free_space_ctl *ctl,
 
        bitmap_set_bits(ctl, info, offset, bytes_to_set);
 
+       /*
+        * We set some bytes, we have no idea what the max extent size is
+        * anymore.
+        */
+       info->max_extent_size = 0;
+
        return bytes_to_set;
 
 }
@@ -1951,12 +1974,19 @@ static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
                      struct btrfs_free_space *info)
 {
        struct btrfs_block_group_cache *block_group = ctl->private;
+       bool forced = false;
+
+#ifdef CONFIG_BTRFS_DEBUG
+       if (btrfs_should_fragment_free_space(block_group->fs_info->extent_root,
+                                            block_group))
+               forced = true;
+#endif
 
        /*
         * If we are below the extents threshold then we can add this as an
         * extent, and don't have to deal with the bitmap
         */
-       if (ctl->free_extents < ctl->extents_thresh) {
+       if (!forced && ctl->free_extents < ctl->extents_thresh) {
                /*
                 * If this block group has some small extents we don't want to
                 * use up all of our free slots in the cache with them, we want
@@ -2661,7 +2691,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
        search_start = min_start;
        search_bytes = bytes;
 
-       err = search_bitmap(ctl, entry, &search_start, &search_bytes);
+       err = search_bitmap(ctl, entry, &search_start, &search_bytes, true);
        if (err) {
                if (search_bytes > *max_extent_size)
                        *max_extent_size = search_bytes;
@@ -2775,6 +2805,7 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
        unsigned long want_bits;
        unsigned long min_bits;
        unsigned long found_bits;
+       unsigned long max_bits = 0;
        unsigned long start = 0;
        unsigned long total_found = 0;
        int ret;
@@ -2784,6 +2815,13 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
        want_bits = bytes_to_bits(bytes, ctl->unit);
        min_bits = bytes_to_bits(min_bytes, ctl->unit);
 
+       /*
+        * Don't bother looking for a cluster in this bitmap if it's heavily
+        * fragmented.
+        */
+       if (entry->max_extent_size &&
+           entry->max_extent_size < cont1_bytes)
+               return -ENOSPC;
 again:
        found_bits = 0;
        for_each_set_bit_from(i, entry->bitmap, BITS_PER_BITMAP) {
@@ -2791,13 +2829,19 @@ again:
                                               BITS_PER_BITMAP, i);
                if (next_zero - i >= min_bits) {
                        found_bits = next_zero - i;
+                       if (found_bits > max_bits)
+                               max_bits = found_bits;
                        break;
                }
+               if (next_zero - i > max_bits)
+                       max_bits = next_zero - i;
                i = next_zero;
        }
 
-       if (!found_bits)
+       if (!found_bits) {
+               entry->max_extent_size = (u64)max_bits * ctl->unit;
                return -ENOSPC;
+       }
 
        if (!total_found) {
                start = i;
@@ -3056,6 +3100,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
        spin_lock_init(&cluster->refill_lock);
        cluster->root = RB_ROOT;
        cluster->max_size = 0;
+       cluster->fragmented = false;
        INIT_LIST_HEAD(&cluster->block_group_list);
        cluster->block_group = NULL;
 }
@@ -3223,7 +3268,7 @@ static int trim_bitmaps(struct btrfs_block_group_cache *block_group,
                }
 
                bytes = minlen;
-               ret2 = search_bitmap(ctl, entry, &start, &bytes);
+               ret2 = search_bitmap(ctl, entry, &start, &bytes, false);
                if (ret2 || start >= end) {
                        spin_unlock(&ctl->tree_lock);
                        mutex_unlock(&ctl->cache_writeout_mutex);
@@ -3376,7 +3421,7 @@ u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root)
                u64 count = 1;
                int ret;
 
-               ret = search_bitmap(ctl, entry, &offset, &count);
+               ret = search_bitmap(ctl, entry, &offset, &count, true);
                /* Logic error; Should be empty if it can't find anything */
                ASSERT(!ret);
 
@@ -3532,6 +3577,7 @@ again:
                spin_lock(&ctl->tree_lock);
                info->offset = offset;
                info->bytes = bytes;
+               info->max_extent_size = 0;
                ret = link_free_space(ctl, info);
                spin_unlock(&ctl->tree_lock);
                if (ret)
@@ -3559,6 +3605,7 @@ again:
        }
 
        bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes);
+
        bytes -= bytes_added;
        offset += bytes_added;
        spin_unlock(&ctl->tree_lock);
@@ -3602,7 +3649,7 @@ have_info:
 
                bit_off = offset;
                bit_bytes = ctl->unit;
-               ret = search_bitmap(ctl, info, &bit_off, &bit_bytes);
+               ret = search_bitmap(ctl, info, &bit_off, &bit_bytes, false);
                if (!ret) {
                        if (bit_off == offset) {
                                ret = 1;
index a16a029ad3b128dcd7723e6d657f43a66a26ed34..f251865eb6f3a628540740a93055e8cdc5aed08c 100644 (file)
@@ -23,6 +23,7 @@ struct btrfs_free_space {
        struct rb_node offset_index;
        u64 offset;
        u64 bytes;
+       u64 max_extent_size;
        unsigned long *bitmap;
        struct list_head list;
 };
index 265e03c73f4daaea4ac1b69ab0a606c63f50895f..be4d22a5022fa09974488a001d859e574f686645 100644 (file)
@@ -157,7 +157,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
         */
        if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
                                            name, name_len, &extref)) {
-               btrfs_std_error(root->fs_info, -ENOENT);
+               btrfs_std_error(root->fs_info, -ENOENT, NULL);
                ret = -EROFS;
                goto out;
        }
index d4a582ac3f730f82299e997d0866e3caecacac7b..767a6056ac45afce29844e469f582baec8ef28cd 100644 (file)
@@ -488,17 +488,17 @@ again:
        /* Just to make sure we have enough space */
        prealloc += 8 * PAGE_CACHE_SIZE;
 
-       ret = btrfs_delalloc_reserve_space(inode, prealloc);
+       ret = btrfs_delalloc_reserve_space(inode, 0, prealloc);
        if (ret)
                goto out_put;
 
        ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
                                              prealloc, prealloc, &alloc_hint);
        if (ret) {
-               btrfs_delalloc_release_space(inode, prealloc);
+               btrfs_delalloc_release_space(inode, 0, prealloc);
                goto out_put;
        }
-       btrfs_free_reserved_data_space(inode, prealloc);
+       btrfs_free_reserved_data_space(inode, 0, prealloc);
 
        ret = btrfs_write_out_ino_cache(root, trans, path, inode);
 out_put:
index 611b66d73e80ba0e5f97b4415595d20f8ae35e1a..4439fbb4ff451bbad4fa03f864ec5ed1ae8625be 100644 (file)
@@ -310,6 +310,13 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
        btrfs_delalloc_release_metadata(inode, end + 1 - start);
        btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
 out:
+       /*
+        * Don't forget to free the reserved space, as for inlined extent
+        * it won't count as data extent, free them directly here.
+        * And at reserve time, it's always aligned to page size, so
+        * just free one page here.
+        */
+       btrfs_qgroup_free_data(inode, 0, PAGE_CACHE_SIZE);
        btrfs_free_path(path);
        btrfs_end_transaction(trans, root);
        return ret;
@@ -1096,6 +1103,9 @@ static noinline void async_cow_submit(struct btrfs_work *work)
        nr_pages = (async_cow->end - async_cow->start + PAGE_CACHE_SIZE) >>
                PAGE_CACHE_SHIFT;
 
+       /*
+        * atomic_sub_return implies a barrier for waitqueue_active
+        */
        if (atomic_sub_return(nr_pages, &root->fs_info->async_delalloc_pages) <
            5 * 1024 * 1024 &&
            waitqueue_active(&root->fs_info->async_submit_wait))
@@ -1766,7 +1776,8 @@ static void btrfs_clear_bit_hook(struct inode *inode,
 
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
                    && do_list && !(state->state & EXTENT_NORESERVE))
-                       btrfs_free_reserved_data_space(inode, len);
+                       btrfs_free_reserved_data_space_noquota(inode,
+                                       state->start, len);
 
                __percpu_counter_add(&root->fs_info->delalloc_bytes, -len,
                                     root->fs_info->delalloc_batch);
@@ -1861,15 +1872,15 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                          u64 bio_offset)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       enum btrfs_wq_endio_type metadata = BTRFS_WQ_ENDIO_DATA;
        int ret = 0;
        int skip_sum;
-       int metadata = 0;
        int async = !atomic_read(&BTRFS_I(inode)->sync_writers);
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
        if (btrfs_is_free_space_inode(inode))
-               metadata = 2;
+               metadata = BTRFS_WQ_ENDIO_FREE_SPACE;
 
        if (!(rw & REQ_WRITE)) {
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
@@ -1989,7 +2000,8 @@ again:
                goto again;
        }
 
-       ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+       ret = btrfs_delalloc_reserve_space(inode, page_start,
+                                          PAGE_CACHE_SIZE);
        if (ret) {
                mapping_set_error(page->mapping, ret);
                end_extent_writepage(page, ret, page_start, page_end);
@@ -2115,7 +2127,13 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        ins.type = BTRFS_EXTENT_ITEM_KEY;
        ret = btrfs_alloc_reserved_file_extent(trans, root,
                                        root->root_key.objectid,
-                                       btrfs_ino(inode), file_pos, &ins);
+                                       btrfs_ino(inode), file_pos,
+                                       ram_bytes, &ins);
+       /*
+        * Release the reserved range from inode dirty range map, as it is
+        * already moved into delayed_ref_head
+        */
+       btrfs_qgroup_release_data(inode, file_pos, ram_bytes);
 out:
        btrfs_free_path(path);
 
@@ -2573,7 +2591,7 @@ again:
        ret = btrfs_inc_extent_ref(trans, root, new->bytenr,
                        new->disk_len, 0,
                        backref->root_id, backref->inum,
-                       new->file_pos, 0);      /* start - extent_offset */
+                       new->file_pos); /* start - extent_offset */
        if (ret) {
                btrfs_abort_transaction(trans, root, ret);
                goto out_free_path;
@@ -2599,7 +2617,6 @@ static void free_sa_defrag_extent(struct new_sa_defrag_extent *new)
                return;
 
        list_for_each_entry_safe(old, tmp, &new->head, list) {
-               list_del(&old->list);
                kfree(old);
        }
        kfree(new);
@@ -2824,6 +2841,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
+
+               /*
+                * For mwrite(mmap + memset to write) case, we still reserve
+                * space for NOCOW range.
+                * As NOCOW won't cause a new delayed ref, just free the space
+                */
+               btrfs_qgroup_free_data(inode, ordered_extent->file_offset,
+                                      ordered_extent->len);
                btrfs_ordered_update_i_size(inode, 0, ordered_extent);
                if (nolock)
                        trans = btrfs_join_transaction_nolock(root);
@@ -3018,8 +3043,6 @@ static int __readpage_endio_check(struct inode *inode,
        char *kaddr;
        u32 csum_expected;
        u32 csum = ~(u32)0;
-       static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
-                                     DEFAULT_RATELIMIT_BURST);
 
        csum_expected = *(((u32 *)io_bio->csum) + icsum);
 
@@ -3032,9 +3055,8 @@ static int __readpage_endio_check(struct inode *inode,
        kunmap_atomic(kaddr);
        return 0;
 zeroit:
-       if (__ratelimit(&_rs))
-               btrfs_warn(BTRFS_I(inode)->root->fs_info,
-                          "csum failed ino %llu off %llu csum %u expected csum %u",
+       btrfs_warn_rl(BTRFS_I(inode)->root->fs_info,
+               "csum failed ino %llu off %llu csum %u expected csum %u",
                           btrfs_ino(inode), start, csum, csum_expected);
        memset(kaddr + pgoff, 1, len);
        flush_dcache_page(page);
@@ -4217,6 +4239,47 @@ static int truncate_space_check(struct btrfs_trans_handle *trans,
 
 }
 
+static int truncate_inline_extent(struct inode *inode,
+                                 struct btrfs_path *path,
+                                 struct btrfs_key *found_key,
+                                 const u64 item_end,
+                                 const u64 new_size)
+{
+       struct extent_buffer *leaf = path->nodes[0];
+       int slot = path->slots[0];
+       struct btrfs_file_extent_item *fi;
+       u32 size = (u32)(new_size - found_key->offset);
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+
+       fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+
+       if (btrfs_file_extent_compression(leaf, fi) != BTRFS_COMPRESS_NONE) {
+               loff_t offset = new_size;
+               loff_t page_end = ALIGN(offset, PAGE_CACHE_SIZE);
+
+               /*
+                * Zero out the remaining of the last page of our inline extent,
+                * instead of directly truncating our inline extent here - that
+                * would be much more complex (decompressing all the data, then
+                * compressing the truncated data, which might be bigger than
+                * the size of the inline extent, resize the extent, etc).
+                * We release the path because to get the page we might need to
+                * read the extent item from disk (data not in the page cache).
+                */
+               btrfs_release_path(path);
+               return btrfs_truncate_page(inode, offset, page_end - offset, 0);
+       }
+
+       btrfs_set_file_extent_ram_bytes(leaf, fi, size);
+       size = btrfs_file_extent_calc_inline_size(size);
+       btrfs_truncate_item(root, path, size, 1);
+
+       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
+               inode_sub_bytes(inode, item_end + 1 - new_size);
+
+       return 0;
+}
+
 /*
  * this can truncate away extent items, csum items and directory items.
  * It starts at a high offset and removes keys until it can't find
@@ -4411,27 +4474,40 @@ search_again:
                         * special encodings
                         */
                        if (!del_item &&
-                           btrfs_file_extent_compression(leaf, fi) == 0 &&
                            btrfs_file_extent_encryption(leaf, fi) == 0 &&
                            btrfs_file_extent_other_encoding(leaf, fi) == 0) {
-                               u32 size = new_size - found_key.offset;
-
-                               if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
-                                       inode_sub_bytes(inode, item_end + 1 -
-                                                       new_size);
 
                                /*
-                                * update the ram bytes to properly reflect
-                                * the new size of our item
+                                * Need to release path in order to truncate a
+                                * compressed extent. So delete any accumulated
+                                * extent items so far.
                                 */
-                               btrfs_set_file_extent_ram_bytes(leaf, fi, size);
-                               size =
-                                   btrfs_file_extent_calc_inline_size(size);
-                               btrfs_truncate_item(root, path, size, 1);
+                               if (btrfs_file_extent_compression(leaf, fi) !=
+                                   BTRFS_COMPRESS_NONE && pending_del_nr) {
+                                       err = btrfs_del_items(trans, root, path,
+                                                             pending_del_slot,
+                                                             pending_del_nr);
+                                       if (err) {
+                                               btrfs_abort_transaction(trans,
+                                                                       root,
+                                                                       err);
+                                               goto error;
+                                       }
+                                       pending_del_nr = 0;
+                               }
+
+                               err = truncate_inline_extent(inode, path,
+                                                            &found_key,
+                                                            item_end,
+                                                            new_size);
+                               if (err) {
+                                       btrfs_abort_transaction(trans,
+                                                               root, err);
+                                       goto error;
+                               }
                        } else if (test_bit(BTRFS_ROOT_REF_COWS,
                                            &root->state)) {
-                               inode_sub_bytes(inode, item_end + 1 -
-                                               found_key.offset);
+                               inode_sub_bytes(inode, item_end + 1 - new_size);
                        }
                }
 delete:
@@ -4461,7 +4537,7 @@ delete:
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes, 0,
                                                btrfs_header_owner(leaf),
-                                               ino, extent_offset, 0);
+                                               ino, extent_offset);
                        BUG_ON(ret);
                        if (btrfs_should_throttle_delayed_refs(trans, root))
                                btrfs_async_run_delayed_refs(root,
@@ -4575,14 +4651,17 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
        if ((offset & (blocksize - 1)) == 0 &&
            (!len || ((len & (blocksize - 1)) == 0)))
                goto out;
-       ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+       ret = btrfs_delalloc_reserve_space(inode,
+                       round_down(from, PAGE_CACHE_SIZE), PAGE_CACHE_SIZE);
        if (ret)
                goto out;
 
 again:
        page = find_or_create_page(mapping, index, mask);
        if (!page) {
-               btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+               btrfs_delalloc_release_space(inode,
+                               round_down(from, PAGE_CACHE_SIZE),
+                               PAGE_CACHE_SIZE);
                ret = -ENOMEM;
                goto out;
        }
@@ -4650,7 +4729,8 @@ again:
 
 out_unlock:
        if (ret)
-               btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+               btrfs_delalloc_release_space(inode, page_start,
+                                            PAGE_CACHE_SIZE);
        unlock_page(page);
        page_cache_release(page);
 out:
@@ -5048,6 +5128,18 @@ static void evict_inode_truncate_pages(struct inode *inode)
                spin_unlock(&io_tree->lock);
 
                lock_extent_bits(io_tree, start, end, 0, &cached_state);
+
+               /*
+                * If still has DELALLOC flag, the extent didn't reach disk,
+                * and its reserved space won't be freed by delayed_ref.
+                * So we need to free its reserved space here.
+                * (Refer to comment in btrfs_invalidatepage, case 2)
+                *
+                * Note, end is the bytenr of last byte, so we need + 1 here.
+                */
+               if (state->state & EXTENT_DELALLOC)
+                       btrfs_qgroup_free_data(inode, start, end - start + 1);
+
                clear_extent_bit(io_tree, start, end,
                                 EXTENT_LOCKED | EXTENT_DIRTY |
                                 EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
@@ -7581,7 +7673,7 @@ unlock:
                        spin_unlock(&BTRFS_I(inode)->lock);
                }
 
-               btrfs_free_reserved_data_space(inode, len);
+               btrfs_free_reserved_data_space(inode, start, len);
                WARN_ON(dio_data->reserve < len);
                dio_data->reserve -= len;
                current->journal_info = dio_data;
@@ -8371,7 +8463,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                        mutex_unlock(&inode->i_mutex);
                        relock = true;
                }
-               ret = btrfs_delalloc_reserve_space(inode, count);
+               ret = btrfs_delalloc_reserve_space(inode, offset, count);
                if (ret)
                        goto out;
                dio_data.outstanding_extents = div64_u64(count +
@@ -8400,10 +8492,10 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                current->journal_info = NULL;
                if (ret < 0 && ret != -EIOCBQUEUED) {
                        if (dio_data.reserve)
-                               btrfs_delalloc_release_space(inode,
-                                                       dio_data.reserve);
+                               btrfs_delalloc_release_space(inode, offset,
+                                                            dio_data.reserve);
                } else if (ret >= 0 && (size_t)ret < count)
-                       btrfs_delalloc_release_space(inode,
+                       btrfs_delalloc_release_space(inode, offset,
                                                     count - (size_t)ret);
        }
 out:
@@ -8562,6 +8654,18 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
                }
        }
 
+       /*
+        * Qgroup reserved space handler
+        * Page here will be either
+        * 1) Already written to disk
+        *    In this case, its reserved space is released from data rsv map
+        *    and will be freed by delayed_ref handler finally.
+        *    So even we call qgroup_free_data(), it won't decrease reserved
+        *    space.
+        * 2) Not written to disk
+        *    This means the reserved space should be freed here.
+        */
+       btrfs_qgroup_free_data(inode, page_start, PAGE_CACHE_SIZE);
        if (!inode_evicting) {
                clear_extent_bit(tree, page_start, page_end,
                                 EXTENT_LOCKED | EXTENT_DIRTY |
@@ -8612,7 +8716,11 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        u64 page_end;
 
        sb_start_pagefault(inode->i_sb);
-       ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+       page_start = page_offset(page);
+       page_end = page_start + PAGE_CACHE_SIZE - 1;
+
+       ret = btrfs_delalloc_reserve_space(inode, page_start,
+                                          PAGE_CACHE_SIZE);
        if (!ret) {
                ret = file_update_time(vma->vm_file);
                reserved = 1;
@@ -8631,8 +8739,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 again:
        lock_page(page);
        size = i_size_read(inode);
-       page_start = page_offset(page);
-       page_end = page_start + PAGE_CACHE_SIZE - 1;
 
        if ((page->mapping != inode->i_mapping) ||
            (page_start >= size)) {
@@ -8709,7 +8815,7 @@ out_unlock:
        }
        unlock_page(page);
 out:
-       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+       btrfs_delalloc_release_space(inode, page_start, PAGE_CACHE_SIZE);
 out_noreserve:
        sb_end_pagefault(inode->i_sb);
        return ret;
@@ -8998,6 +9104,7 @@ void btrfs_destroy_inode(struct inode *inode)
                        btrfs_put_ordered_extent(ordered);
                }
        }
+       btrfs_qgroup_check_reserved_leak(inode);
        inode_tree_del(inode);
        btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
 free:
@@ -9634,6 +9741,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
        u64 cur_offset = start;
        u64 i_size;
        u64 cur_bytes;
+       u64 last_alloc = (u64)-1;
        int ret = 0;
        bool own_trans = true;
 
@@ -9650,6 +9758,13 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
 
                cur_bytes = min(num_bytes, 256ULL * 1024 * 1024);
                cur_bytes = max(cur_bytes, min_size);
+               /*
+                * If we are severely fragmented we could end up with really
+                * small allocations, so if the allocator is returning small
+                * chunks lets make its job easier by only searching for those
+                * sized chunks.
+                */
+               cur_bytes = min(cur_bytes, last_alloc);
                ret = btrfs_reserve_extent(root, cur_bytes, min_size, 0,
                                           *alloc_hint, &ins, 1, 0);
                if (ret) {
@@ -9658,6 +9773,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
                        break;
                }
 
+               last_alloc = ins.offset;
                ret = insert_reserved_file_extent(trans, inode,
                                                  cur_offset, ins.objectid,
                                                  ins.offset, ins.offset,
index 8d20f3b1cab0abfa7b5f2bc4b8646c094a9353a5..da94138eb85eb3f15f127b08c54a113715956686 100644 (file)
@@ -1120,7 +1120,8 @@ static int cluster_pages_for_defrag(struct inode *inode,
        page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1);
 
        ret = btrfs_delalloc_reserve_space(inode,
-                                          page_cnt << PAGE_CACHE_SHIFT);
+                       start_index << PAGE_CACHE_SHIFT,
+                       page_cnt << PAGE_CACHE_SHIFT);
        if (ret)
                return ret;
        i_done = 0;
@@ -1210,7 +1211,8 @@ again:
                BTRFS_I(inode)->outstanding_extents++;
                spin_unlock(&BTRFS_I(inode)->lock);
                btrfs_delalloc_release_space(inode,
-                                    (page_cnt - i_done) << PAGE_CACHE_SHIFT);
+                               start_index << PAGE_CACHE_SHIFT,
+                               (page_cnt - i_done) << PAGE_CACHE_SHIFT);
        }
 
 
@@ -1235,7 +1237,9 @@ out:
                unlock_page(pages[i]);
                page_cache_release(pages[i]);
        }
-       btrfs_delalloc_release_space(inode, page_cnt << PAGE_CACHE_SHIFT);
+       btrfs_delalloc_release_space(inode,
+                       start_index << PAGE_CACHE_SHIFT,
+                       page_cnt << PAGE_CACHE_SHIFT);
        return ret;
 
 }
@@ -1342,7 +1346,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                        break;
 
                if (btrfs_defrag_cancelled(root->fs_info)) {
-                       printk(KERN_DEBUG "BTRFS: defrag_file cancelled\n");
+                       btrfs_debug(root->fs_info, "defrag_file cancelled");
                        ret = -EAGAIN;
                        break;
                }
@@ -1579,7 +1583,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        new_size = div_u64(new_size, root->sectorsize);
        new_size *= root->sectorsize;
 
-       printk_in_rcu(KERN_INFO "BTRFS: new size for %s is %llu\n",
+       btrfs_info_in_rcu(root->fs_info, "new size for %s is %llu",
                      rcu_str_deref(device->name), new_size);
 
        if (new_size > old_size) {
@@ -2081,7 +2085,7 @@ static noinline int search_ioctl(struct inode *inode,
                key.offset = (u64)-1;
                root = btrfs_read_fs_root_no_name(info, &key);
                if (IS_ERR(root)) {
-                       printk(KERN_ERR "BTRFS: could not find root %llu\n",
+                       btrfs_err(info, "could not find root %llu",
                               sk->tree_id);
                        btrfs_free_path(path);
                        return -ENOENT;
@@ -2221,7 +2225,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
        key.offset = (u64)-1;
        root = btrfs_read_fs_root_no_name(info, &key);
        if (IS_ERR(root)) {
-               printk(KERN_ERR "BTRFS: could not find root %llu\n", tree_id);
+               btrfs_err(info, "could not find root %llu", tree_id);
                ret = -ENOENT;
                goto out;
        }
@@ -2699,7 +2703,6 @@ static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
 {
        struct btrfs_ioctl_fs_info_args *fi_args;
        struct btrfs_device *device;
-       struct btrfs_device *next;
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        int ret = 0;
 
@@ -2711,7 +2714,7 @@ static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
        fi_args->num_devices = fs_devices->num_devices;
        memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid));
 
-       list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
+       list_for_each_entry(device, &fs_devices->devices, dev_list) {
                if (device->devid > fi_args->max_id)
                        fi_args->max_id = device->devid;
        }
@@ -3203,41 +3206,6 @@ out:
        return ret;
 }
 
-/* Helper to check and see if this root currently has a ref on the given disk
- * bytenr.  If it does then we need to update the quota for this root.  This
- * doesn't do anything if quotas aren't enabled.
- */
-static int check_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                    u64 disko)
-{
-       struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem);
-       struct ulist *roots;
-       struct ulist_iterator uiter;
-       struct ulist_node *root_node = NULL;
-       int ret;
-
-       if (!root->fs_info->quota_enabled)
-               return 1;
-
-       btrfs_get_tree_mod_seq(root->fs_info, &tree_mod_seq_elem);
-       ret = btrfs_find_all_roots(trans, root->fs_info, disko,
-                                  tree_mod_seq_elem.seq, &roots);
-       if (ret < 0)
-               goto out;
-       ret = 0;
-       ULIST_ITER_INIT(&uiter);
-       while ((root_node = ulist_next(roots, &uiter))) {
-               if (root_node->val == root->objectid) {
-                       ret = 1;
-                       break;
-               }
-       }
-       ulist_free(roots);
-out:
-       btrfs_put_tree_mod_seq(root->fs_info, &tree_mod_seq_elem);
-       return ret;
-}
-
 static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
                                     struct inode *inode,
                                     u64 endoff,
@@ -3328,6 +3296,150 @@ static void clone_update_extent_map(struct inode *inode,
                        &BTRFS_I(inode)->runtime_flags);
 }
 
+/*
+ * Make sure we do not end up inserting an inline extent into a file that has
+ * already other (non-inline) extents. If a file has an inline extent it can
+ * not have any other extents and the (single) inline extent must start at the
+ * file offset 0. Failing to respect these rules will lead to file corruption,
+ * resulting in EIO errors on read/write operations, hitting BUG_ON's in mm, etc
+ *
+ * We can have extents that have been already written to disk or we can have
+ * dirty ranges still in delalloc, in which case the extent maps and items are
+ * created only when we run delalloc, and the delalloc ranges might fall outside
+ * the range we are currently locking in the inode's io tree. So we check the
+ * inode's i_size because of that (i_size updates are done while holding the
+ * i_mutex, which we are holding here).
+ * We also check to see if the inode has a size not greater than "datal" but has
+ * extents beyond it, due to an fallocate with FALLOC_FL_KEEP_SIZE (and we are
+ * protected against such concurrent fallocate calls by the i_mutex).
+ *
+ * If the file has no extents but a size greater than datal, do not allow the
+ * copy because we would need turn the inline extent into a non-inline one (even
+ * with NO_HOLES enabled). If we find our destination inode only has one inline
+ * extent, just overwrite it with the source inline extent if its size is less
+ * than the source extent's size, or we could copy the source inline extent's
+ * data into the destination inode's inline extent if the later is greater then
+ * the former.
+ */
+static int clone_copy_inline_extent(struct inode *src,
+                                   struct inode *dst,
+                                   struct btrfs_trans_handle *trans,
+                                   struct btrfs_path *path,
+                                   struct btrfs_key *new_key,
+                                   const u64 drop_start,
+                                   const u64 datal,
+                                   const u64 skip,
+                                   const u64 size,
+                                   char *inline_data)
+{
+       struct btrfs_root *root = BTRFS_I(dst)->root;
+       const u64 aligned_end = ALIGN(new_key->offset + datal,
+                                     root->sectorsize);
+       int ret;
+       struct btrfs_key key;
+
+       if (new_key->offset > 0)
+               return -EOPNOTSUPP;
+
+       key.objectid = btrfs_ino(dst);
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = 0;
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       if (ret < 0) {
+               return ret;
+       } else if (ret > 0) {
+               if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               return ret;
+                       else if (ret > 0)
+                               goto copy_inline_extent;
+               }
+               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+               if (key.objectid == btrfs_ino(dst) &&
+                   key.type == BTRFS_EXTENT_DATA_KEY) {
+                       ASSERT(key.offset > 0);
+                       return -EOPNOTSUPP;
+               }
+       } else if (i_size_read(dst) <= datal) {
+               struct btrfs_file_extent_item *ei;
+               u64 ext_len;
+
+               /*
+                * If the file size is <= datal, make sure there are no other
+                * extents following (can happen do to an fallocate call with
+                * the flag FALLOC_FL_KEEP_SIZE).
+                */
+               ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                   struct btrfs_file_extent_item);
+               /*
+                * If it's an inline extent, it can not have other extents
+                * following it.
+                */
+               if (btrfs_file_extent_type(path->nodes[0], ei) ==
+                   BTRFS_FILE_EXTENT_INLINE)
+                       goto copy_inline_extent;
+
+               ext_len = btrfs_file_extent_num_bytes(path->nodes[0], ei);
+               if (ext_len > aligned_end)
+                       return -EOPNOTSUPP;
+
+               ret = btrfs_next_item(root, path);
+               if (ret < 0) {
+                       return ret;
+               } else if (ret == 0) {
+                       btrfs_item_key_to_cpu(path->nodes[0], &key,
+                                             path->slots[0]);
+                       if (key.objectid == btrfs_ino(dst) &&
+                           key.type == BTRFS_EXTENT_DATA_KEY)
+                               return -EOPNOTSUPP;
+               }
+       }
+
+copy_inline_extent:
+       /*
+        * We have no extent items, or we have an extent at offset 0 which may
+        * or may not be inlined. All these cases are dealt the same way.
+        */
+       if (i_size_read(dst) > datal) {
+               /*
+                * If the destination inode has an inline extent...
+                * This would require copying the data from the source inline
+                * extent into the beginning of the destination's inline extent.
+                * But this is really complex, both extents can be compressed
+                * or just one of them, which would require decompressing and
+                * re-compressing data (which could increase the new compressed
+                * size, not allowing the compressed data to fit anymore in an
+                * inline extent).
+                * So just don't support this case for now (it should be rare,
+                * we are not really saving space when cloning inline extents).
+                */
+               return -EOPNOTSUPP;
+       }
+
+       btrfs_release_path(path);
+       ret = btrfs_drop_extents(trans, root, dst, drop_start, aligned_end, 1);
+       if (ret)
+               return ret;
+       ret = btrfs_insert_empty_item(trans, root, path, new_key, size);
+       if (ret)
+               return ret;
+
+       if (skip) {
+               const u32 start = btrfs_file_extent_calc_inline_size(0);
+
+               memmove(inline_data + start, inline_data + start + skip, datal);
+       }
+
+       write_extent_buffer(path->nodes[0], inline_data,
+                           btrfs_item_ptr_offset(path->nodes[0],
+                                                 path->slots[0]),
+                           size);
+       inode_add_bytes(dst, datal);
+
+       return 0;
+}
+
 /**
  * btrfs_clone() - clone a range from inode file to another
  *
@@ -3352,9 +3464,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        u32 nritems;
        int slot;
        int ret;
-       int no_quota;
        const u64 len = olen_aligned;
-       u64 last_disko = 0;
        u64 last_dest_end = destoff;
 
        ret = -ENOMEM;
@@ -3400,7 +3510,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
 
                nritems = btrfs_header_nritems(path->nodes[0]);
 process_slot:
-               no_quota = 1;
                if (path->slots[0] >= nritems) {
                        ret = btrfs_next_leaf(BTRFS_I(src)->root, path);
                        if (ret < 0)
@@ -3552,35 +3661,13 @@ process_slot:
                                btrfs_set_file_extent_num_bytes(leaf, extent,
                                                                datal);
 
-                               /*
-                                * We need to look up the roots that point at
-                                * this bytenr and see if the new root does.  If
-                                * it does not we need to make sure we update
-                                * quotas appropriately.
-                                */
-                               if (disko && root != BTRFS_I(src)->root &&
-                                   disko != last_disko) {
-                                       no_quota = check_ref(trans, root,
-                                                            disko);
-                                       if (no_quota < 0) {
-                                               btrfs_abort_transaction(trans,
-                                                                       root,
-                                                                       ret);
-                                               btrfs_end_transaction(trans,
-                                                                     root);
-                                               ret = no_quota;
-                                               goto out;
-                                       }
-                               }
-
                                if (disko) {
                                        inode_add_bytes(inode, datal);
                                        ret = btrfs_inc_extent_ref(trans, root,
                                                        disko, diskl, 0,
                                                        root->root_key.objectid,
                                                        btrfs_ino(inode),
-                                                       new_key.offset - datao,
-                                                       no_quota);
+                                                       new_key.offset - datao);
                                        if (ret) {
                                                btrfs_abort_transaction(trans,
                                                                        root,
@@ -3594,21 +3681,6 @@ process_slot:
                        } else if (type == BTRFS_FILE_EXTENT_INLINE) {
                                u64 skip = 0;
                                u64 trim = 0;
-                               u64 aligned_end = 0;
-
-                               /*
-                                * Don't copy an inline extent into an offset
-                                * greater than zero. Having an inline extent
-                                * at such an offset results in chaos as btrfs
-                                * isn't prepared for such cases. Just skip
-                                * this case for the same reasons as commented
-                                * at btrfs_ioctl_clone().
-                                */
-                               if (last_dest_end > 0) {
-                                       ret = -EOPNOTSUPP;
-                                       btrfs_end_transaction(trans, root);
-                                       goto out;
-                               }
 
                                if (off > key.offset) {
                                        skip = off - key.offset;
@@ -3626,42 +3698,22 @@ process_slot:
                                size -= skip + trim;
                                datal -= skip + trim;
 
-                               aligned_end = ALIGN(new_key.offset + datal,
-                                                   root->sectorsize);
-                               ret = btrfs_drop_extents(trans, root, inode,
-                                                        drop_start,
-                                                        aligned_end,
-                                                        1);
+                               ret = clone_copy_inline_extent(src, inode,
+                                                              trans, path,
+                                                              &new_key,
+                                                              drop_start,
+                                                              datal,
+                                                              skip, size, buf);
                                if (ret) {
                                        if (ret != -EOPNOTSUPP)
                                                btrfs_abort_transaction(trans,
-                                                       root, ret);
-                                       btrfs_end_transaction(trans, root);
-                                       goto out;
-                               }
-
-                               ret = btrfs_insert_empty_item(trans, root, path,
-                                                             &new_key, size);
-                               if (ret) {
-                                       btrfs_abort_transaction(trans, root,
-                                                               ret);
+                                                                       root,
+                                                                       ret);
                                        btrfs_end_transaction(trans, root);
                                        goto out;
                                }
-
-                               if (skip) {
-                                       u32 start =
-                                         btrfs_file_extent_calc_inline_size(0);
-                                       memmove(buf+start, buf+start+skip,
-                                               datal);
-                               }
-
                                leaf = path->nodes[0];
                                slot = path->slots[0];
-                               write_extent_buffer(leaf, buf,
-                                           btrfs_item_ptr_offset(leaf, slot),
-                                           size);
-                               inode_add_bytes(inode, datal);
                        }
 
                        /* If we have an implicit hole (NO_HOLES feature). */
@@ -4814,7 +4866,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
        /* update qgroup status and info */
        err = btrfs_run_qgroups(trans, root->fs_info);
        if (err < 0)
-               btrfs_error(root->fs_info, ret,
+               btrfs_std_error(root->fs_info, ret,
                            "failed to update qgroup status and info\n");
        err = btrfs_end_transaction(trans, root);
        if (err && !ret)
index d7e6baf1b2054f1998608902385bc5016020c2cf..8077461fc56ab256d8d02838ac3c345408edf5a4 100644 (file)
@@ -79,6 +79,9 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
                write_lock(&eb->lock);
                WARN_ON(atomic_read(&eb->spinning_writers));
                atomic_inc(&eb->spinning_writers);
+               /*
+                * atomic_dec_and_test implies a barrier for waitqueue_active
+                */
                if (atomic_dec_and_test(&eb->blocking_writers) &&
                    waitqueue_active(&eb->write_lock_wq))
                        wake_up(&eb->write_lock_wq);
@@ -86,6 +89,9 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
                BUG_ON(atomic_read(&eb->blocking_readers) == 0);
                read_lock(&eb->lock);
                atomic_inc(&eb->spinning_readers);
+               /*
+                * atomic_dec_and_test implies a barrier for waitqueue_active
+                */
                if (atomic_dec_and_test(&eb->blocking_readers) &&
                    waitqueue_active(&eb->read_lock_wq))
                        wake_up(&eb->read_lock_wq);
@@ -229,6 +235,9 @@ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb)
        }
        btrfs_assert_tree_read_locked(eb);
        WARN_ON(atomic_read(&eb->blocking_readers) == 0);
+       /*
+        * atomic_dec_and_test implies a barrier for waitqueue_active
+        */
        if (atomic_dec_and_test(&eb->blocking_readers) &&
            waitqueue_active(&eb->read_lock_wq))
                wake_up(&eb->read_lock_wq);
@@ -280,6 +289,9 @@ void btrfs_tree_unlock(struct extent_buffer *eb)
        if (blockers) {
                WARN_ON(atomic_read(&eb->spinning_writers));
                atomic_dec(&eb->blocking_writers);
+               /*
+                * Make sure counter is updated before we wake up waiters.
+                */
                smp_mb();
                if (waitqueue_active(&eb->write_lock_wq))
                        wake_up(&eb->write_lock_wq);
index 52170cf1757e3d25192a6cf6211a9d2edaa52751..8c27292ea9ea09361d94389c5a7f7a146bb8a925 100644 (file)
@@ -345,6 +345,9 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,
 
        if (entry->bytes_left == 0) {
                ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
+               /*
+                * Implicit memory barrier after test_and_set_bit
+                */
                if (waitqueue_active(&entry->wait))
                        wake_up(&entry->wait);
        } else {
@@ -409,6 +412,9 @@ have_entry:
 
        if (entry->bytes_left == 0) {
                ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
+               /*
+                * Implicit memory barrier after test_and_set_bit
+                */
                if (waitqueue_active(&entry->wait))
                        wake_up(&entry->wait);
        } else {
@@ -484,15 +490,16 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
 
        spin_lock_irq(&log->log_extents_lock[index]);
        while (!list_empty(&log->logged_list[index])) {
+               struct inode *inode;
                ordered = list_first_entry(&log->logged_list[index],
                                           struct btrfs_ordered_extent,
                                           log_list);
                list_del_init(&ordered->log_list);
+               inode = ordered->inode;
                spin_unlock_irq(&log->log_extents_lock[index]);
 
                if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) &&
                    !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) {
-                       struct inode *inode = ordered->inode;
                        u64 start = ordered->file_offset;
                        u64 end = ordered->file_offset + ordered->len - 1;
 
@@ -503,20 +510,25 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
                                                   &ordered->flags));
 
                /*
-                * If our ordered extent completed it means it updated the
-                * fs/subvol and csum trees already, so no need to make the
-                * current transaction's commit wait for it, as we end up
-                * holding memory unnecessarily and delaying the inode's iput
-                * until the transaction commit (we schedule an iput for the
-                * inode when the ordered extent's refcount drops to 0), which
-                * prevents it from being evictable until the transaction
-                * commits.
+                * In order to keep us from losing our ordered extent
+                * information when committing the transaction we have to make
+                * sure that any logged extents are completed when we go to
+                * commit the transaction.  To do this we simply increase the
+                * current transactions pending_ordered counter and decrement it
+                * when the ordered extent completes.
                 */
-               if (test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags))
-                       btrfs_put_ordered_extent(ordered);
-               else
-                       list_add_tail(&ordered->trans_list, &trans->ordered);
-
+               if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) {
+                       struct btrfs_ordered_inode_tree *tree;
+
+                       tree = &BTRFS_I(inode)->ordered_tree;
+                       spin_lock_irq(&tree->lock);
+                       if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) {
+                               set_bit(BTRFS_ORDERED_PENDING, &ordered->flags);
+                               atomic_inc(&trans->transaction->pending_ordered);
+                       }
+                       spin_unlock_irq(&tree->lock);
+               }
+               btrfs_put_ordered_extent(ordered);
                spin_lock_irq(&log->log_extents_lock[index]);
        }
        spin_unlock_irq(&log->log_extents_lock[index]);
@@ -578,6 +590,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        struct btrfs_ordered_inode_tree *tree;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct rb_node *node;
+       bool dec_pending_ordered = false;
 
        tree = &BTRFS_I(inode)->ordered_tree;
        spin_lock_irq(&tree->lock);
@@ -587,8 +600,37 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        if (tree->last == node)
                tree->last = NULL;
        set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
+       if (test_and_clear_bit(BTRFS_ORDERED_PENDING, &entry->flags))
+               dec_pending_ordered = true;
        spin_unlock_irq(&tree->lock);
 
+       /*
+        * The current running transaction is waiting on us, we need to let it
+        * know that we're complete and wake it up.
+        */
+       if (dec_pending_ordered) {
+               struct btrfs_transaction *trans;
+
+               /*
+                * The checks for trans are just a formality, it should be set,
+                * but if it isn't we don't want to deref/assert under the spin
+                * lock, so be nice and check if trans is set, but ASSERT() so
+                * if it isn't set a developer will notice.
+                */
+               spin_lock(&root->fs_info->trans_lock);
+               trans = root->fs_info->running_transaction;
+               if (trans)
+                       atomic_inc(&trans->use_count);
+               spin_unlock(&root->fs_info->trans_lock);
+
+               ASSERT(trans);
+               if (trans) {
+                       if (atomic_dec_and_test(&trans->pending_ordered))
+                               wake_up(&trans->pending_wait);
+                       btrfs_put_transaction(trans);
+               }
+       }
+
        spin_lock(&root->ordered_extent_lock);
        list_del_init(&entry->root_extent_list);
        root->nr_ordered_extents--;
index 7176cc0fe43f7074ffa3c959bb3a7eae0d3b90e2..23c96059cef26a6292847a051b893f254cc472b3 100644 (file)
@@ -73,6 +73,8 @@ struct btrfs_ordered_sum {
 
 #define BTRFS_ORDERED_LOGGED 10 /* Set when we've waited on this ordered extent
                                 * in the logging code. */
+#define BTRFS_ORDERED_PENDING 11 /* We are waiting for this ordered extent to
+                                 * complete in the current transaction. */
 struct btrfs_ordered_extent {
        /* logical offset in the file */
        u64 file_offset;
index dca137b04095fc509390b2c02d4ca6ad1752ee74..f9e60231f6854545d514d8df53b8ba21be92762e 100644 (file)
@@ -49,18 +49,16 @@ static struct prop_handler prop_handlers[] = {
                .extract = prop_compression_extract,
                .inheritable = 1
        },
-       {
-               .xattr_name = NULL
-       }
 };
 
 void __init btrfs_props_init(void)
 {
-       struct prop_handler *p;
+       int i;
 
        hash_init(prop_handlers_ht);
 
-       for (p = &prop_handlers[0]; p->xattr_name; p++) {
+       for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
+               struct prop_handler *p = &prop_handlers[i];
                u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
 
                hash_add(prop_handlers_ht, &p->node, h);
@@ -301,15 +299,16 @@ static int inherit_props(struct btrfs_trans_handle *trans,
                         struct inode *inode,
                         struct inode *parent)
 {
-       const struct prop_handler *h;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
+       int i;
 
        if (!test_bit(BTRFS_INODE_HAS_PROPS,
                      &BTRFS_I(parent)->runtime_flags))
                return 0;
 
-       for (h = &prop_handlers[0]; h->xattr_name; h++) {
+       for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
+               const struct prop_handler *h = &prop_handlers[i];
                const char *value;
                u64 num_bytes;
 
index d904ee1c53497034ed6685b8e12f40d0880aaaca..46476c226395e777045a2303a1ada87b9e4b4a78 100644 (file)
@@ -1652,10 +1652,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
                        }
                }
 
-               /* For exclusive extent, free its reserved bytes too */
-               if (nr_old_roots == 0 && nr_new_roots == 1 &&
-                   cur_new_count == nr_new_roots)
-                       qg->reserved -= num_bytes;
                if (dirty)
                        qgroup_dirty(fs_info, qg);
        }
@@ -2035,7 +2031,7 @@ out:
        return ret;
 }
 
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
+static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 {
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *qgroup;
@@ -2116,14 +2112,13 @@ out:
        return ret;
 }
 
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
+void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
+                              u64 ref_root, u64 num_bytes)
 {
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *qgroup;
-       struct btrfs_fs_info *fs_info = root->fs_info;
        struct ulist_node *unode;
        struct ulist_iterator uiter;
-       u64 ref_root = root->root_key.objectid;
        int ret = 0;
 
        if (!is_fstree(ref_root))
@@ -2169,6 +2164,11 @@ out:
        spin_unlock(&fs_info->qgroup_lock);
 }
 
+static inline void qgroup_free(struct btrfs_root *root, u64 num_bytes)
+{
+       return btrfs_qgroup_free_refroot(root->fs_info, root->objectid,
+                                        num_bytes);
+}
 void assert_qgroups_uptodate(struct btrfs_trans_handle *trans)
 {
        if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq)
@@ -2188,10 +2188,10 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans)
  */
 static int
 qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
-                  struct btrfs_trans_handle *trans,
-                  struct extent_buffer *scratch_leaf)
+                  struct btrfs_trans_handle *trans)
 {
        struct btrfs_key found;
+       struct extent_buffer *scratch_leaf = NULL;
        struct ulist *roots = NULL;
        struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem);
        u64 num_bytes;
@@ -2229,7 +2229,15 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
        fs_info->qgroup_rescan_progress.objectid = found.objectid + 1;
 
        btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
-       memcpy(scratch_leaf, path->nodes[0], sizeof(*scratch_leaf));
+       scratch_leaf = btrfs_clone_extent_buffer(path->nodes[0]);
+       if (!scratch_leaf) {
+               ret = -ENOMEM;
+               mutex_unlock(&fs_info->qgroup_rescan_lock);
+               goto out;
+       }
+       extent_buffer_get(scratch_leaf);
+       btrfs_tree_read_lock(scratch_leaf);
+       btrfs_set_lock_blocking_rw(scratch_leaf, BTRFS_READ_LOCK);
        slot = path->slots[0];
        btrfs_release_path(path);
        mutex_unlock(&fs_info->qgroup_rescan_lock);
@@ -2255,6 +2263,10 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
                        goto out;
        }
 out:
+       if (scratch_leaf) {
+               btrfs_tree_read_unlock_blocking(scratch_leaf);
+               free_extent_buffer(scratch_leaf);
+       }
        btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
 
        return ret;
@@ -2266,16 +2278,12 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
                                                     qgroup_rescan_work);
        struct btrfs_path *path;
        struct btrfs_trans_handle *trans = NULL;
-       struct extent_buffer *scratch_leaf = NULL;
        int err = -ENOMEM;
        int ret = 0;
 
        path = btrfs_alloc_path();
        if (!path)
                goto out;
-       scratch_leaf = kmalloc(sizeof(*scratch_leaf), GFP_NOFS);
-       if (!scratch_leaf)
-               goto out;
 
        err = 0;
        while (!err) {
@@ -2287,8 +2295,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
                if (!fs_info->quota_enabled) {
                        err = -EINTR;
                } else {
-                       err = qgroup_rescan_leaf(fs_info, path, trans,
-                                                scratch_leaf);
+                       err = qgroup_rescan_leaf(fs_info, path, trans);
                }
                if (err > 0)
                        btrfs_commit_transaction(trans, fs_info->fs_root);
@@ -2297,7 +2304,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
        }
 
 out:
-       kfree(scratch_leaf);
        btrfs_free_path(path);
 
        mutex_lock(&fs_info->qgroup_rescan_lock);
@@ -2486,3 +2492,190 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info)
                btrfs_queue_work(fs_info->qgroup_rescan_workers,
                                 &fs_info->qgroup_rescan_work);
 }
+
+/*
+ * Reserve qgroup space for range [start, start + len).
+ *
+ * This function will either reserve space from related qgroups or doing
+ * nothing if the range is already reserved.
+ *
+ * Return 0 for successful reserve
+ * Return <0 for error (including -EQUOT)
+ *
+ * NOTE: this function may sleep for memory allocation.
+ */
+int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct extent_changeset changeset;
+       struct ulist_node *unode;
+       struct ulist_iterator uiter;
+       int ret;
+
+       if (!root->fs_info->quota_enabled || !is_fstree(root->objectid) ||
+           len == 0)
+               return 0;
+
+       changeset.bytes_changed = 0;
+       changeset.range_changed = ulist_alloc(GFP_NOFS);
+       ret = set_record_extent_bits(&BTRFS_I(inode)->io_tree, start,
+                       start + len -1, EXTENT_QGROUP_RESERVED, GFP_NOFS,
+                       &changeset);
+       trace_btrfs_qgroup_reserve_data(inode, start, len,
+                                       changeset.bytes_changed,
+                                       QGROUP_RESERVE);
+       if (ret < 0)
+               goto cleanup;
+       ret = qgroup_reserve(root, changeset.bytes_changed);
+       if (ret < 0)
+               goto cleanup;
+
+       ulist_free(changeset.range_changed);
+       return ret;
+
+cleanup:
+       /* cleanup already reserved ranges */
+       ULIST_ITER_INIT(&uiter);
+       while ((unode = ulist_next(changeset.range_changed, &uiter)))
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val,
+                                unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL,
+                                GFP_NOFS);
+       ulist_free(changeset.range_changed);
+       return ret;
+}
+
+static int __btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len,
+                                      int free)
+{
+       struct extent_changeset changeset;
+       int trace_op = QGROUP_RELEASE;
+       int ret;
+
+       changeset.bytes_changed = 0;
+       changeset.range_changed = ulist_alloc(GFP_NOFS);
+       if (!changeset.range_changed)
+               return -ENOMEM;
+
+       ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, start, 
+                       start + len -1, EXTENT_QGROUP_RESERVED, GFP_NOFS,
+                       &changeset);
+       if (ret < 0)
+               goto out;
+
+       if (free) {
+               qgroup_free(BTRFS_I(inode)->root, changeset.bytes_changed);
+               trace_op = QGROUP_FREE;
+       }
+       trace_btrfs_qgroup_release_data(inode, start, len,
+                                       changeset.bytes_changed, trace_op);
+out:
+       ulist_free(changeset.range_changed);
+       return ret;
+}
+
+/*
+ * Free a reserved space range from io_tree and related qgroups
+ *
+ * Should be called when a range of pages get invalidated before reaching disk.
+ * Or for error cleanup case.
+ *
+ * For data written to disk, use btrfs_qgroup_release_data().
+ *
+ * NOTE: This function may sleep for memory allocation.
+ */
+int btrfs_qgroup_free_data(struct inode *inode, u64 start, u64 len)
+{
+       return __btrfs_qgroup_release_data(inode, start, len, 1);
+}
+
+/*
+ * Release a reserved space range from io_tree only.
+ *
+ * Should be called when a range of pages get written to disk and corresponding
+ * FILE_EXTENT is inserted into corresponding root.
+ *
+ * Since new qgroup accounting framework will only update qgroup numbers at
+ * commit_transaction() time, its reserved space shouldn't be freed from
+ * related qgroups.
+ *
+ * But we should release the range from io_tree, to allow further write to be
+ * COWed.
+ *
+ * NOTE: This function may sleep for memory allocation.
+ */
+int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
+{
+       return __btrfs_qgroup_release_data(inode, start, len, 0);
+}
+
+int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes)
+{
+       int ret;
+
+       if (!root->fs_info->quota_enabled || !is_fstree(root->objectid) ||
+           num_bytes == 0)
+               return 0;
+
+       BUG_ON(num_bytes != round_down(num_bytes, root->nodesize));
+       ret = qgroup_reserve(root, num_bytes);
+       if (ret < 0)
+               return ret;
+       atomic_add(num_bytes, &root->qgroup_meta_rsv);
+       return ret;
+}
+
+void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
+{
+       int reserved;
+
+       if (!root->fs_info->quota_enabled || !is_fstree(root->objectid))
+               return;
+
+       reserved = atomic_xchg(&root->qgroup_meta_rsv, 0);
+       if (reserved == 0)
+               return;
+       qgroup_free(root, reserved);
+}
+
+void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
+{
+       if (!root->fs_info->quota_enabled || !is_fstree(root->objectid))
+               return;
+
+       BUG_ON(num_bytes != round_down(num_bytes, root->nodesize));
+       WARN_ON(atomic_read(&root->qgroup_meta_rsv) < num_bytes);
+       atomic_sub(num_bytes, &root->qgroup_meta_rsv);
+       qgroup_free(root, num_bytes);
+}
+
+/*
+ * Check qgroup reserved space leaking, normally at destory inode
+ * time
+ */
+void btrfs_qgroup_check_reserved_leak(struct inode *inode)
+{
+       struct extent_changeset changeset;
+       struct ulist_node *unode;
+       struct ulist_iterator iter;
+       int ret;
+
+       changeset.bytes_changed = 0;
+       changeset.range_changed = ulist_alloc(GFP_NOFS);
+       if (WARN_ON(!changeset.range_changed))
+               return;
+
+       ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
+                       EXTENT_QGROUP_RESERVED, GFP_NOFS, &changeset);
+
+       WARN_ON(ret < 0);
+       if (WARN_ON(changeset.bytes_changed)) {
+               ULIST_ITER_INIT(&iter);
+               while ((unode = ulist_next(changeset.range_changed, &iter))) {
+                       btrfs_warn(BTRFS_I(inode)->root->fs_info,
+                               "leaking qgroup reserved space, ino: %lu, start: %llu, end: %llu",
+                               inode->i_ino, unode->val, unode->aux);
+               }
+               qgroup_free(BTRFS_I(inode)->root, changeset.bytes_changed);
+       }
+       ulist_free(changeset.range_changed);
+}
index 6387dcfa354c6ecac672a543bf1d6b8e587e911b..ecb2c143ef756bd0356e3968b3f9f13fe5ac21cd 100644 (file)
@@ -33,6 +33,13 @@ struct btrfs_qgroup_extent_record {
        struct ulist *old_roots;
 };
 
+/*
+ * For qgroup event trace points only
+ */
+#define QGROUP_RESERVE         (1<<0)
+#define QGROUP_RELEASE         (1<<1)
+#define QGROUP_FREE            (1<<2)
+
 int btrfs_quota_enable(struct btrfs_trans_handle *trans,
                       struct btrfs_fs_info *fs_info);
 int btrfs_quota_disable(struct btrfs_trans_handle *trans,
@@ -71,9 +78,18 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
                         struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
                         struct btrfs_qgroup_inherit *inherit);
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes);
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes);
-
+void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
+                              u64 ref_root, u64 num_bytes);
+/*
+ * TODO: Add proper trace point for it, as btrfs_qgroup_free() is
+ * called by everywhere, can't provide good trace for delayed ref case.
+ */
+static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info,
+                                                u64 ref_root, u64 num_bytes)
+{
+       btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes);
+       trace_btrfs_qgroup_free_delayed_ref(ref_root, num_bytes);
+}
 void assert_qgroups_uptodate(struct btrfs_trans_handle *trans);
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
@@ -81,4 +97,13 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
                               u64 rfer, u64 excl);
 #endif
 
+/* New io_tree based accurate qgroup reserve API */
+int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len);
+int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len);
+int btrfs_qgroup_free_data(struct inode *inode, u64 start, u64 len);
+
+int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes);
+void btrfs_qgroup_free_meta_all(struct btrfs_root *root);
+void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes);
+void btrfs_qgroup_check_reserved_leak(struct inode *inode);
 #endif /* __BTRFS_QGROUP__ */
index fcf7265ca46fd84a65b647619f4e07ba996d7a9f..1a33d3eb36de184e4cbcf72efb26687857c70051 100644 (file)
@@ -810,7 +810,11 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio)
                        }
 
                        goto done_nolock;
-               } else  if (waitqueue_active(&h->wait)) {
+                       /*
+                        * The barrier for this waitqueue_active is not needed,
+                        * we're protected by h->lock and can't miss a wakeup.
+                        */
+               } else if (waitqueue_active(&h->wait)) {
                        spin_unlock(&rbio->bio_list_lock);
                        spin_unlock_irqrestore(&h->lock, flags);
                        wake_up(&h->wait);
index 4645cd16d5ba22d94396eec0f00e1243371eeb7c..619f92963e27102fb47a6f119b65451bdf959bef 100644 (file)
@@ -569,7 +569,7 @@ static int reada_add_block(struct reada_control *rc, u64 logical,
        rec = kzalloc(sizeof(*rec), GFP_NOFS);
        if (!rec) {
                reada_extent_put(root->fs_info, re);
-               return -1;
+               return -ENOMEM;
        }
 
        rec->rc = rc;
@@ -918,6 +918,7 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root,
        u64 start;
        u64 generation;
        int level;
+       int ret;
        struct extent_buffer *node;
        static struct btrfs_key max_key = {
                .objectid = (u64)-1,
@@ -943,9 +944,10 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root,
        generation = btrfs_header_generation(node);
        free_extent_buffer(node);
 
-       if (reada_add_block(rc, start, &max_key, level, generation)) {
+       ret = reada_add_block(rc, start, &max_key, level, generation);
+       if (ret) {
                kfree(rc);
-               return ERR_PTR(-ENOMEM);
+               return ERR_PTR(ret);
        }
 
        reada_start_machine(root->fs_info);
index 303babeef50579e66f48cb94d9668cb8a1731a6b..b4ca5454ef1a7ebc4fcb8eec476701bc8496a050 100644 (file)
@@ -1716,7 +1716,7 @@ 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, 1);
+                                          key.objectid, key.offset);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        break;
@@ -1724,7 +1724,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
 
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        parent, btrfs_header_owner(leaf),
-                                       key.objectid, key.offset, 1);
+                                       key.objectid, key.offset);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        break;
@@ -1900,23 +1900,21 @@ again:
 
                ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize,
                                        path->nodes[level]->start,
-                                       src->root_key.objectid, level - 1, 0,
-                                       1);
+                                       src->root_key.objectid, level - 1, 0);
                BUG_ON(ret);
                ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize,
                                        0, dest->root_key.objectid, level - 1,
-                                       0, 1);
+                                       0);
                BUG_ON(ret);
 
                ret = btrfs_free_extent(trans, src, new_bytenr, blocksize,
                                        path->nodes[level]->start,
-                                       src->root_key.objectid, level - 1, 0,
-                                       1);
+                                       src->root_key.objectid, level - 1, 0);
                BUG_ON(ret);
 
                ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize,
                                        0, dest->root_key.objectid, level - 1,
-                                       0, 1);
+                                       0);
                BUG_ON(ret);
 
                btrfs_unlock_up_safe(path, 0);
@@ -2418,7 +2416,7 @@ again:
        }
 out:
        if (ret) {
-               btrfs_std_error(root->fs_info, ret);
+               btrfs_std_error(root->fs_info, ret, NULL);
                if (!list_empty(&reloc_roots))
                        free_reloc_roots(&reloc_roots);
 
@@ -2745,7 +2743,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, 1);
+                                               node->level, 0);
                        BUG_ON(ret);
 
                        ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
@@ -3034,8 +3032,8 @@ int prealloc_file_extent_cluster(struct inode *inode,
        BUG_ON(cluster->start != cluster->boundary[0]);
        mutex_lock(&inode->i_mutex);
 
-       ret = btrfs_check_data_free_space(inode, cluster->end +
-                                         1 - cluster->start, 0);
+       ret = btrfs_check_data_free_space(inode, cluster->start,
+                                         cluster->end + 1 - cluster->start);
        if (ret)
                goto out;
 
@@ -3056,8 +3054,8 @@ int prealloc_file_extent_cluster(struct inode *inode,
                        break;
                nr++;
        }
-       btrfs_free_reserved_data_space(inode, cluster->end +
-                                      1 - cluster->start);
+       btrfs_free_reserved_data_space(inode, cluster->start,
+                                      cluster->end + 1 - cluster->start);
 out:
        mutex_unlock(&inode->i_mutex);
        return ret;
index 360a728a639fec403893c6847e1f7859a47dff13..7cf8509deda7c0ea6e98af02a8ab0acafbe016b2 100644 (file)
@@ -45,12 +45,13 @@ static void btrfs_read_root_item(struct extent_buffer *eb, int slot,
        if (!need_reset && btrfs_root_generation(item)
                != btrfs_root_generation_v2(item)) {
                if (btrfs_root_generation_v2(item) != 0) {
-                       printk(KERN_WARNING "BTRFS: mismatching "
+                       btrfs_warn(eb->fs_info,
+                                       "mismatching "
                                        "generation and generation_v2 "
                                        "found in root item. This root "
                                        "was probably mounted with an "
                                        "older kernel. Resetting all "
-                                       "new fields.\n");
+                                       "new fields.");
                }
                need_reset = 1;
        }
@@ -141,7 +142,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
        int ret;
        int slot;
        unsigned long ptr;
-       int old_len;
+       u32 old_len;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -283,7 +284,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                        trans = btrfs_join_transaction(tree_root);
                        if (IS_ERR(trans)) {
                                err = PTR_ERR(trans);
-                               btrfs_error(tree_root->fs_info, err,
+                               btrfs_std_error(tree_root->fs_info, err,
                                            "Failed to start trans to delete "
                                            "orphan item");
                                break;
@@ -292,7 +293,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                                                    root_key.objectid);
                        btrfs_end_transaction(trans, tree_root);
                        if (err) {
-                               btrfs_error(tree_root->fs_info, err,
+                               btrfs_std_error(tree_root->fs_info, err,
                                            "Failed to delete root orphan "
                                            "item");
                                break;
index a39f5d1144e8e0fe90b459f3c5528d5672be0d4a..550de89a8661af8fdb1c08783ffadde680c138ec 100644 (file)
@@ -580,9 +580,9 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
         * hold all of the paths here
         */
        for (i = 0; i < ipath->fspath->elem_cnt; ++i)
-               printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
+               btrfs_warn_in_rcu(fs_info, "%s at logical %llu on dev "
                        "%s, sector %llu, root %llu, inode %llu, offset %llu, "
-                       "length %llu, links %u (path: %s)\n", swarn->errstr,
+                       "length %llu, links %u (path: %s)", swarn->errstr,
                        swarn->logical, rcu_str_deref(swarn->dev->name),
                        (unsigned long long)swarn->sector, root, inum, offset,
                        min(isize - offset, (u64)PAGE_SIZE), nlink,
@@ -592,9 +592,9 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
        return 0;
 
 err:
-       printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
+       btrfs_warn_in_rcu(fs_info, "%s at logical %llu on dev "
                "%s, sector %llu, root %llu, inode %llu, offset %llu: path "
-               "resolving failed with ret=%d\n", swarn->errstr,
+               "resolving failed with ret=%d", swarn->errstr,
                swarn->logical, rcu_str_deref(swarn->dev->name),
                (unsigned long long)swarn->sector, root, inum, offset, ret);
 
@@ -649,10 +649,10 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
                        ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
                                                      item_size, &ref_root,
                                                      &ref_level);
-                       printk_in_rcu(KERN_WARNING
-                               "BTRFS: %s at logical %llu on dev %s, "
+                       btrfs_warn_in_rcu(fs_info,
+                               "%s at logical %llu on dev %s, "
                                "sector %llu: metadata %s (level %d) in tree "
-                               "%llu\n", errstr, swarn.logical,
+                               "%llu", errstr, swarn.logical,
                                rcu_str_deref(dev->name),
                                (unsigned long long)swarn.sector,
                                ref_level ? "node" : "leaf",
@@ -850,8 +850,8 @@ out:
                btrfs_dev_replace_stats_inc(
                        &sctx->dev_root->fs_info->dev_replace.
                        num_uncorrectable_read_errors);
-               printk_ratelimited_in_rcu(KERN_ERR "BTRFS: "
-                   "unable to fixup (nodatasum) error at logical %llu on dev %s\n",
+               btrfs_err_rl_in_rcu(sctx->dev_root->fs_info,
+                   "unable to fixup (nodatasum) error at logical %llu on dev %s",
                        fixup->logical, rcu_str_deref(fixup->dev->name));
        }
 
@@ -1230,8 +1230,8 @@ corrected_error:
                        sctx->stat.corrected_errors++;
                        sblock_to_check->data_corrected = 1;
                        spin_unlock(&sctx->stat_lock);
-                       printk_ratelimited_in_rcu(KERN_ERR
-                               "BTRFS: fixed up error at logical %llu on dev %s\n",
+                       btrfs_err_rl_in_rcu(fs_info,
+                               "fixed up error at logical %llu on dev %s",
                                logical, rcu_str_deref(dev->name));
                }
        } else {
@@ -1239,8 +1239,8 @@ did_not_correct_error:
                spin_lock(&sctx->stat_lock);
                sctx->stat.uncorrectable_errors++;
                spin_unlock(&sctx->stat_lock);
-               printk_ratelimited_in_rcu(KERN_ERR
-                       "BTRFS: unable to fixup (regular) error at logical %llu on dev %s\n",
+               btrfs_err_rl_in_rcu(fs_info,
+                       "unable to fixup (regular) error at logical %llu on dev %s",
                        logical, rcu_str_deref(dev->name));
        }
 
@@ -1626,9 +1626,9 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                int ret;
 
                if (!page_bad->dev->bdev) {
-                       printk_ratelimited(KERN_WARNING "BTRFS: "
+                       btrfs_warn_rl(sblock_bad->sctx->dev_root->fs_info,
                                "scrub_repair_page_from_good_copy(bdev == NULL) "
-                               "is unexpected!\n");
+                               "is unexpected");
                        return -EIO;
                }
 
@@ -2201,15 +2201,15 @@ static void scrub_missing_raid56_worker(struct btrfs_work *work)
                spin_lock(&sctx->stat_lock);
                sctx->stat.read_errors++;
                spin_unlock(&sctx->stat_lock);
-               printk_ratelimited_in_rcu(KERN_ERR
-                       "BTRFS: I/O error rebulding logical %llu for dev %s\n",
+               btrfs_err_rl_in_rcu(fs_info,
+                       "IO error rebuilding logical %llu for dev %s",
                        logical, rcu_str_deref(dev->name));
        } else if (sblock->header_error || sblock->checksum_error) {
                spin_lock(&sctx->stat_lock);
                sctx->stat.uncorrectable_errors++;
                spin_unlock(&sctx->stat_lock);
-               printk_ratelimited_in_rcu(KERN_ERR
-                       "BTRFS: failed to rebuild valid logical %llu for dev %s\n",
+               btrfs_err_rl_in_rcu(fs_info,
+                       "failed to rebuild valid logical %llu for dev %s",
                        logical, rcu_str_deref(dev->name));
        } else {
                scrub_write_block_to_dev_replace(sblock);
@@ -4375,8 +4375,8 @@ static int write_page_nocow(struct scrub_ctx *sctx,
        if (!dev)
                return -EIO;
        if (!dev->bdev) {
-               printk_ratelimited(KERN_WARNING
-                       "BTRFS: scrub write_page_nocow(bdev == NULL) is unexpected!\n");
+               btrfs_warn_rl(dev->dev_root->fs_info,
+                       "scrub write_page_nocow(bdev == NULL) is unexpected");
                return -EIO;
        }
        bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
index a739b825bdd364cfa9cbf16edc9f978a68feb95f..355a458cba1abe29efb3410a6ae93261052ba1e9 100644 (file)
@@ -1434,16 +1434,6 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, "
        }
 
        if (cur_clone_root) {
-               if (compressed != BTRFS_COMPRESS_NONE) {
-                       /*
-                        * Offsets given by iterate_extent_inodes() are relative
-                        * to the start of the extent, we need to add logical
-                        * offset from the file extent item.
-                        * (See why at backref.c:check_extent_in_eb())
-                        */
-                       cur_clone_root->offset += btrfs_file_extent_offset(eb,
-                                                                          fi);
-               }
                *found = cur_clone_root;
                ret = 0;
        } else {
@@ -2353,8 +2343,14 @@ static int send_subvol_begin(struct send_ctx *sctx)
        }
 
        TLV_PUT_STRING(sctx, BTRFS_SEND_A_PATH, name, namelen);
-       TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID,
-                       sctx->send_root->root_item.uuid);
+
+       if (!btrfs_is_empty_uuid(sctx->send_root->root_item.received_uuid))
+               TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID,
+                           sctx->send_root->root_item.received_uuid);
+       else
+               TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID,
+                           sctx->send_root->root_item.uuid);
+
        TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID,
                    le64_to_cpu(sctx->send_root->root_item.ctransid));
        if (parent_root) {
@@ -2564,7 +2560,7 @@ verbose_printk("btrfs: send_create_inode %llu\n", ino);
        } else if (S_ISSOCK(mode)) {
                cmd = BTRFS_SEND_C_MKSOCK;
        } else {
-               printk(KERN_WARNING "btrfs: unexpected inode type %o",
+               btrfs_warn(sctx->send_root->fs_info, "unexpected inode type %o",
                                (int)(mode & S_IFMT));
                ret = -ENOTSUPP;
                goto out;
@@ -4687,6 +4683,171 @@ tlv_put_failure:
        return ret;
 }
 
+static int send_extent_data(struct send_ctx *sctx,
+                           const u64 offset,
+                           const u64 len)
+{
+       u64 sent = 0;
+
+       if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
+               return send_update_extent(sctx, offset, len);
+
+       while (sent < len) {
+               u64 size = len - sent;
+               int ret;
+
+               if (size > BTRFS_SEND_READ_SIZE)
+                       size = BTRFS_SEND_READ_SIZE;
+               ret = send_write(sctx, offset + sent, size);
+               if (ret < 0)
+                       return ret;
+               if (!ret)
+                       break;
+               sent += ret;
+       }
+       return 0;
+}
+
+static int clone_range(struct send_ctx *sctx,
+                      struct clone_root *clone_root,
+                      const u64 disk_byte,
+                      u64 data_offset,
+                      u64 offset,
+                      u64 len)
+{
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       int ret;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * We can't send a clone operation for the entire range if we find
+        * extent items in the respective range in the source file that
+        * refer to different extents or if we find holes.
+        * So check for that and do a mix of clone and regular write/copy
+        * operations if needed.
+        *
+        * Example:
+        *
+        * mkfs.btrfs -f /dev/sda
+        * mount /dev/sda /mnt
+        * xfs_io -f -c "pwrite -S 0xaa 0K 100K" /mnt/foo
+        * cp --reflink=always /mnt/foo /mnt/bar
+        * xfs_io -c "pwrite -S 0xbb 50K 50K" /mnt/foo
+        * btrfs subvolume snapshot -r /mnt /mnt/snap
+        *
+        * If when we send the snapshot and we are processing file bar (which
+        * has a higher inode number than foo) we blindly send a clone operation
+        * for the [0, 100K[ range from foo to bar, the receiver ends up getting
+        * a file bar that matches the content of file foo - iow, doesn't match
+        * the content from bar in the original filesystem.
+        */
+       key.objectid = clone_root->ino;
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = clone_root->offset;
+       ret = btrfs_search_slot(NULL, clone_root->root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (ret > 0 && path->slots[0] > 0) {
+               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1);
+               if (key.objectid == clone_root->ino &&
+                   key.type == BTRFS_EXTENT_DATA_KEY)
+                       path->slots[0]--;
+       }
+
+       while (true) {
+               struct extent_buffer *leaf = path->nodes[0];
+               int slot = path->slots[0];
+               struct btrfs_file_extent_item *ei;
+               u8 type;
+               u64 ext_len;
+               u64 clone_len;
+
+               if (slot >= btrfs_header_nritems(leaf)) {
+                       ret = btrfs_next_leaf(clone_root->root, path);
+                       if (ret < 0)
+                               goto out;
+                       else if (ret > 0)
+                               break;
+                       continue;
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+
+               /*
+                * We might have an implicit trailing hole (NO_HOLES feature
+                * enabled). We deal with it after leaving this loop.
+                */
+               if (key.objectid != clone_root->ino ||
+                   key.type != BTRFS_EXTENT_DATA_KEY)
+                       break;
+
+               ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+               type = btrfs_file_extent_type(leaf, ei);
+               if (type == BTRFS_FILE_EXTENT_INLINE) {
+                       ext_len = btrfs_file_extent_inline_len(leaf, slot, ei);
+                       ext_len = PAGE_CACHE_ALIGN(ext_len);
+               } else {
+                       ext_len = btrfs_file_extent_num_bytes(leaf, ei);
+               }
+
+               if (key.offset + ext_len <= clone_root->offset)
+                       goto next;
+
+               if (key.offset > clone_root->offset) {
+                       /* Implicit hole, NO_HOLES feature enabled. */
+                       u64 hole_len = key.offset - clone_root->offset;
+
+                       if (hole_len > len)
+                               hole_len = len;
+                       ret = send_extent_data(sctx, offset, hole_len);
+                       if (ret < 0)
+                               goto out;
+
+                       len -= hole_len;
+                       if (len == 0)
+                               break;
+                       offset += hole_len;
+                       clone_root->offset += hole_len;
+                       data_offset += hole_len;
+               }
+
+               if (key.offset >= clone_root->offset + len)
+                       break;
+
+               clone_len = min_t(u64, ext_len, len);
+
+               if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte &&
+                   btrfs_file_extent_offset(leaf, ei) == data_offset)
+                       ret = send_clone(sctx, offset, clone_len, clone_root);
+               else
+                       ret = send_extent_data(sctx, offset, clone_len);
+
+               if (ret < 0)
+                       goto out;
+
+               len -= clone_len;
+               if (len == 0)
+                       break;
+               offset += clone_len;
+               clone_root->offset += clone_len;
+               data_offset += clone_len;
+next:
+               path->slots[0]++;
+       }
+
+       if (len > 0)
+               ret = send_extent_data(sctx, offset, len);
+       else
+               ret = 0;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 static int send_write_or_clone(struct send_ctx *sctx,
                               struct btrfs_path *path,
                               struct btrfs_key *key,
@@ -4695,9 +4856,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
        int ret = 0;
        struct btrfs_file_extent_item *ei;
        u64 offset = key->offset;
-       u64 pos = 0;
        u64 len;
-       u32 l;
        u8 type;
        u64 bs = sctx->send_root->fs_info->sb->s_blocksize;
 
@@ -4725,22 +4884,15 @@ static int send_write_or_clone(struct send_ctx *sctx,
        }
 
        if (clone_root && IS_ALIGNED(offset + len, bs)) {
-               ret = send_clone(sctx, offset, len, clone_root);
-       } else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) {
-               ret = send_update_extent(sctx, offset, len);
+               u64 disk_byte;
+               u64 data_offset;
+
+               disk_byte = btrfs_file_extent_disk_bytenr(path->nodes[0], ei);
+               data_offset = btrfs_file_extent_offset(path->nodes[0], ei);
+               ret = clone_range(sctx, clone_root, disk_byte, data_offset,
+                                 offset, len);
        } else {
-               while (pos < len) {
-                       l = len - pos;
-                       if (l > BTRFS_SEND_READ_SIZE)
-                               l = BTRFS_SEND_READ_SIZE;
-                       ret = send_write(sctx, pos + offset, l);
-                       if (ret < 0)
-                               goto out;
-                       if (!ret)
-                               break;
-                       pos += ret;
-               }
-               ret = 0;
+               ret = send_extent_data(sctx, offset, len);
        }
 out:
        return ret;
index 11d1eab9234dc818244d1c1bbecd6d25981f4890..24154e422945167f474557887c62acaf6ed0779c 100644 (file)
@@ -130,7 +130,6 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
        }
 }
 
-#ifdef CONFIG_PRINTK
 /*
  * __btrfs_std_error decodes expected errors from the caller and
  * invokes the approciate error response.
@@ -140,7 +139,9 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                       unsigned int line, int errno, const char *fmt, ...)
 {
        struct super_block *sb = fs_info->sb;
+#ifdef CONFIG_PRINTK
        const char *errstr;
+#endif
 
        /*
         * Special case: if the error is EROFS, and we're already
@@ -149,6 +150,7 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
        if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
                return;
 
+#ifdef CONFIG_PRINTK
        errstr = btrfs_decode_error(errno);
        if (fmt) {
                struct va_format vaf;
@@ -166,6 +168,7 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                printk(KERN_CRIT "BTRFS: error (device %s) in %s:%d: errno=%d %s\n",
                        sb->s_id, function, line, errno, errstr);
        }
+#endif
 
        /* Don't go through full error handling during mount */
        save_error_info(fs_info);
@@ -173,6 +176,7 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                btrfs_handle_error(fs_info);
 }
 
+#ifdef CONFIG_PRINTK
 static const char * const logtypes[] = {
        "emergency",
        "alert",
@@ -212,27 +216,6 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
 
        va_end(args);
 }
-
-#else
-
-void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
-                      unsigned int line, int errno, const char *fmt, ...)
-{
-       struct super_block *sb = fs_info->sb;
-
-       /*
-        * Special case: if the error is EROFS, and we're already
-        * under MS_RDONLY, then it is safe here.
-        */
-       if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
-               return;
-
-       /* Don't go through full error handling during mount */
-       if (sb->s_flags & MS_BORN) {
-               save_error_info(fs_info);
-               btrfs_handle_error(fs_info);
-       }
-}
 #endif
 
 /*
@@ -320,6 +303,9 @@ enum {
        Opt_commit_interval, Opt_barrier, Opt_nodefrag, Opt_nodiscard,
        Opt_noenospc_debug, Opt_noflushoncommit, Opt_acl, Opt_datacow,
        Opt_datasum, Opt_treelog, Opt_noinode_cache,
+#ifdef CONFIG_BTRFS_DEBUG
+       Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
+#endif
        Opt_err,
 };
 
@@ -372,6 +358,11 @@ static match_table_t tokens = {
        {Opt_rescan_uuid_tree, "rescan_uuid_tree"},
        {Opt_fatal_errors, "fatal_errors=%s"},
        {Opt_commit_interval, "commit=%d"},
+#ifdef CONFIG_BTRFS_DEBUG
+       {Opt_fragment_data, "fragment=data"},
+       {Opt_fragment_metadata, "fragment=metadata"},
+       {Opt_fragment_all, "fragment=all"},
+#endif
        {Opt_err, NULL},
 };
 
@@ -738,6 +729,22 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
                        }
                        break;
+#ifdef CONFIG_BTRFS_DEBUG
+               case Opt_fragment_all:
+                       btrfs_info(root->fs_info, "fragmenting all space");
+                       btrfs_set_opt(info->mount_opt, FRAGMENT_DATA);
+                       btrfs_set_opt(info->mount_opt, FRAGMENT_METADATA);
+                       break;
+               case Opt_fragment_metadata:
+                       btrfs_info(root->fs_info, "fragmenting metadata");
+                       btrfs_set_opt(info->mount_opt,
+                                     FRAGMENT_METADATA);
+                       break;
+               case Opt_fragment_data:
+                       btrfs_info(root->fs_info, "fragmenting data");
+                       btrfs_set_opt(info->mount_opt, FRAGMENT_DATA);
+                       break;
+#endif
                case Opt_err:
                        btrfs_info(root->fs_info, "unrecognized mount option '%s'", p);
                        ret = -EINVAL;
@@ -1189,6 +1196,12 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",fatal_errors=panic");
        if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
                seq_printf(seq, ",commit=%d", info->commit_interval);
+#ifdef CONFIG_BTRFS_DEBUG
+       if (btrfs_test_opt(root, FRAGMENT_DATA))
+               seq_puts(seq, ",fragment=data");
+       if (btrfs_test_opt(root, FRAGMENT_METADATA))
+               seq_puts(seq, ",fragment=metadata");
+#endif
        seq_printf(seq, ",subvolid=%llu",
                  BTRFS_I(d_inode(dentry))->root->root_key.objectid);
        seq_puts(seq, ",subvol=");
index 603b0cc2b9bbf627f0b07fec3dad216164e6ddf3..e0ac85949067c30191ce3635e2a65edbe8a56361 100644 (file)
@@ -437,24 +437,24 @@ static const struct attribute *btrfs_attrs[] = {
        NULL,
 };
 
-static void btrfs_release_super_kobj(struct kobject *kobj)
+static void btrfs_release_fsid_kobj(struct kobject *kobj)
 {
        struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
 
-       memset(&fs_devs->super_kobj, 0, sizeof(struct kobject));
+       memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
        complete(&fs_devs->kobj_unregister);
 }
 
 static struct kobj_type btrfs_ktype = {
        .sysfs_ops      = &kobj_sysfs_ops,
-       .release        = btrfs_release_super_kobj,
+       .release        = btrfs_release_fsid_kobj,
 };
 
 static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj)
 {
        if (kobj->ktype != &btrfs_ktype)
                return NULL;
-       return container_of(kobj, struct btrfs_fs_devices, super_kobj);
+       return container_of(kobj, struct btrfs_fs_devices, fsid_kobj);
 }
 
 static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
@@ -502,12 +502,12 @@ static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
                        attrs[0] = &fa->kobj_attr.attr;
                        if (add) {
                                int ret;
-                               ret = sysfs_merge_group(&fs_info->fs_devices->super_kobj,
+                               ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj,
                                                        &agroup);
                                if (ret)
                                        return ret;
                        } else
-                               sysfs_unmerge_group(&fs_info->fs_devices->super_kobj,
+                               sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
                                                    &agroup);
                }
 
@@ -523,9 +523,9 @@ static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
                fs_devs->device_dir_kobj = NULL;
        }
 
-       if (fs_devs->super_kobj.state_initialized) {
-               kobject_del(&fs_devs->super_kobj);
-               kobject_put(&fs_devs->super_kobj);
+       if (fs_devs->fsid_kobj.state_initialized) {
+               kobject_del(&fs_devs->fsid_kobj);
+               kobject_put(&fs_devs->fsid_kobj);
                wait_for_completion(&fs_devs->kobj_unregister);
        }
 }
@@ -545,7 +545,7 @@ void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
        }
 }
 
-void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
+void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
 {
        btrfs_reset_fs_info_ptr(fs_info);
 
@@ -555,9 +555,9 @@ void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
                kobject_put(fs_info->space_info_kobj);
        }
        addrm_unknown_feature_attrs(fs_info, false);
-       sysfs_remove_group(&fs_info->fs_devices->super_kobj, &btrfs_feature_attr_group);
-       sysfs_remove_files(&fs_info->fs_devices->super_kobj, btrfs_attrs);
-       btrfs_kobj_rm_device(fs_info->fs_devices, NULL);
+       sysfs_remove_group(&fs_info->fs_devices->fsid_kobj, &btrfs_feature_attr_group);
+       sysfs_remove_files(&fs_info->fs_devices->fsid_kobj, btrfs_attrs);
+       btrfs_sysfs_rm_device_link(fs_info->fs_devices, NULL);
 }
 
 const char * const btrfs_feature_set_names[3] = {
@@ -637,7 +637,7 @@ static void init_feature_attrs(void)
 
 /* when one_device is NULL, it removes all device links */
 
-int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices,
+int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices,
                struct btrfs_device *one_device)
 {
        struct hd_struct *disk;
@@ -675,7 +675,7 @@ int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs)
 {
        if (!fs_devs->device_dir_kobj)
                fs_devs->device_dir_kobj = kobject_create_and_add("devices",
-                                               &fs_devs->super_kobj);
+                                               &fs_devs->fsid_kobj);
 
        if (!fs_devs->device_dir_kobj)
                return -ENOMEM;
@@ -683,7 +683,7 @@ int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs)
        return 0;
 }
 
-int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices,
+int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices,
                                struct btrfs_device *one_device)
 {
        int error = 0;
@@ -730,31 +730,31 @@ int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs,
        int error;
 
        init_completion(&fs_devs->kobj_unregister);
-       fs_devs->super_kobj.kset = btrfs_kset;
-       error = kobject_init_and_add(&fs_devs->super_kobj,
+       fs_devs->fsid_kobj.kset = btrfs_kset;
+       error = kobject_init_and_add(&fs_devs->fsid_kobj,
                                &btrfs_ktype, parent, "%pU", fs_devs->fsid);
        return error;
 }
 
-int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
+int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
 {
        int error;
        struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
-       struct kobject *super_kobj = &fs_devs->super_kobj;
+       struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
 
        btrfs_set_fs_info_ptr(fs_info);
 
-       error = btrfs_kobj_add_device(fs_devs, NULL);
+       error = btrfs_sysfs_add_device_link(fs_devs, NULL);
        if (error)
                return error;
 
-       error = sysfs_create_files(super_kobj, btrfs_attrs);
+       error = sysfs_create_files(fsid_kobj, btrfs_attrs);
        if (error) {
-               btrfs_kobj_rm_device(fs_devs, NULL);
+               btrfs_sysfs_rm_device_link(fs_devs, NULL);
                return error;
        }
 
-       error = sysfs_create_group(super_kobj,
+       error = sysfs_create_group(fsid_kobj,
                                   &btrfs_feature_attr_group);
        if (error)
                goto failure;
@@ -764,7 +764,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
                goto failure;
 
        fs_info->space_info_kobj = kobject_create_and_add("allocation",
-                                                 super_kobj);
+                                                 fsid_kobj);
        if (!fs_info->space_info_kobj) {
                error = -ENOMEM;
                goto failure;
@@ -776,7 +776,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
 
        return 0;
 failure:
-       btrfs_sysfs_remove_one(fs_info);
+       btrfs_sysfs_remove_mounted(fs_info);
        return error;
 }
 
index 6392527bcc15d5e56b66d39a3faac72fba730e2f..9c09522125a6b26d0577e139c38ebad7ca5c8331 100644 (file)
@@ -82,9 +82,9 @@ char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags);
 extern const char * const btrfs_feature_set_names[3];
 extern struct kobj_type space_info_ktype;
 extern struct kobj_type btrfs_raid_ktype;
-int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices,
+int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices,
                struct btrfs_device *one_device);
-int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices,
+int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices,
                 struct btrfs_device *one_device);
 int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs,
                                struct kobject *parent);
index 2299bfde39eec666fe1b0876733746a76673f5a5..c8c3d70c31ffad4e02acd04e0f7dcaa54ad0fe2b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include "btrfs-tests.h"
 #include "../ctree.h"
+#include "../disk-io.h"
 #include "../free-space-cache.h"
 
 #define BITS_PER_BITMAP                (PAGE_CACHE_SIZE * 8)
@@ -35,6 +36,12 @@ static struct btrfs_block_group_cache *init_test_block_group(void)
                kfree(cache);
                return NULL;
        }
+       cache->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!cache->fs_info) {
+               kfree(cache->free_space_ctl);
+               kfree(cache);
+               return NULL;
+       }
 
        cache->key.objectid = 0;
        cache->key.offset = 1024 * 1024 * 1024;
@@ -879,7 +886,8 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
 int btrfs_test_free_space_cache(void)
 {
        struct btrfs_block_group_cache *cache;
-       int ret;
+       struct btrfs_root *root = NULL;
+       int ret = -ENOMEM;
 
        test_msg("Running btrfs free space cache tests\n");
 
@@ -889,6 +897,17 @@ int btrfs_test_free_space_cache(void)
                return 0;
        }
 
+       root = btrfs_alloc_dummy_root();
+       if (!root)
+               goto out;
+
+       root->fs_info = btrfs_alloc_dummy_fs_info();
+       if (!root->fs_info)
+               goto out;
+
+       root->fs_info->extent_root = root;
+       cache->fs_info = root->fs_info;
+
        ret = test_extents(cache);
        if (ret)
                goto out;
@@ -904,6 +923,7 @@ out:
        __btrfs_remove_free_space_cache(cache->free_space_ctl);
        kfree(cache->free_space_ctl);
        kfree(cache);
+       btrfs_free_dummy_root(root);
        test_msg("Free space cache tests finished\n");
        return ret;
 }
index a5b06442f0bf9d1630f201da3e0eb5c0422e8cc9..418c6a2ad7d88658f8624d99a1ba0e9e84c13d45 100644 (file)
@@ -82,6 +82,12 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
 static void clear_btree_io_tree(struct extent_io_tree *tree)
 {
        spin_lock(&tree->lock);
+       /*
+        * Do a single barrier for the waitqueue_active check here, the state
+        * of the waitqueue should not change once clear_btree_io_tree is
+        * called.
+        */
+       smp_mb();
        while (!RB_EMPTY_ROOT(&tree->state)) {
                struct rb_node *node;
                struct extent_state *state;
@@ -226,25 +232,22 @@ loop:
        extwriter_counter_init(cur_trans, type);
        init_waitqueue_head(&cur_trans->writer_wait);
        init_waitqueue_head(&cur_trans->commit_wait);
+       init_waitqueue_head(&cur_trans->pending_wait);
        cur_trans->state = TRANS_STATE_RUNNING;
        /*
         * One for this trans handle, one so it will live on until we
         * commit the transaction.
         */
        atomic_set(&cur_trans->use_count, 2);
-       cur_trans->have_free_bgs = 0;
+       atomic_set(&cur_trans->pending_ordered, 0);
+       cur_trans->flags = 0;
        cur_trans->start_time = get_seconds();
-       cur_trans->dirty_bg_run = 0;
+
+       memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs));
 
        cur_trans->delayed_refs.href_root = RB_ROOT;
        cur_trans->delayed_refs.dirty_extent_root = RB_ROOT;
        atomic_set(&cur_trans->delayed_refs.num_entries, 0);
-       cur_trans->delayed_refs.num_heads_ready = 0;
-       cur_trans->delayed_refs.pending_csums = 0;
-       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.qgroup_to_skip = 0;
 
        /*
         * although the tree mod log is per file system and not per transaction,
@@ -264,7 +267,6 @@ loop:
        INIT_LIST_HEAD(&cur_trans->pending_snapshots);
        INIT_LIST_HEAD(&cur_trans->pending_chunks);
        INIT_LIST_HEAD(&cur_trans->switch_commits);
-       INIT_LIST_HEAD(&cur_trans->pending_ordered);
        INIT_LIST_HEAD(&cur_trans->dirty_bgs);
        INIT_LIST_HEAD(&cur_trans->io_bgs);
        INIT_LIST_HEAD(&cur_trans->dropped_roots);
@@ -447,8 +449,8 @@ static inline bool need_reserve_reloc_root(struct btrfs_root *root)
 }
 
 static struct btrfs_trans_handle *
-start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
-                 enum btrfs_reserve_flush_enum flush)
+start_transaction(struct btrfs_root *root, unsigned int num_items,
+                 unsigned int type, enum btrfs_reserve_flush_enum flush)
 {
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
@@ -478,13 +480,10 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
         * the appropriate flushing if need be.
         */
        if (num_items > 0 && root != root->fs_info->chunk_root) {
-               if (root->fs_info->quota_enabled &&
-                   is_fstree(root->root_key.objectid)) {
-                       qgroup_reserved = num_items * root->nodesize;
-                       ret = btrfs_qgroup_reserve(root, qgroup_reserved);
-                       if (ret)
-                               return ERR_PTR(ret);
-               }
+               qgroup_reserved = num_items * root->nodesize;
+               ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved);
+               if (ret)
+                       return ERR_PTR(ret);
 
                num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
                /*
@@ -502,7 +501,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
                        goto reserve_fail;
        }
 again:
-       h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
+       h = kmem_cache_zalloc(btrfs_trans_handle_cachep, GFP_NOFS);
        if (!h) {
                ret = -ENOMEM;
                goto alloc_fail;
@@ -543,26 +542,13 @@ again:
 
        h->transid = cur_trans->transid;
        h->transaction = cur_trans;
-       h->blocks_used = 0;
-       h->bytes_reserved = 0;
-       h->chunk_bytes_reserved = 0;
        h->root = root;
-       h->delayed_ref_updates = 0;
        h->use_count = 1;
-       h->adding_csums = 0;
-       h->block_rsv = NULL;
-       h->orig_rsv = NULL;
-       h->aborted = 0;
-       h->qgroup_reserved = 0;
-       h->delayed_ref_elem.seq = 0;
+
        h->type = type;
-       h->allocating_chunk = false;
        h->can_flush_pending_bgs = true;
-       h->reloc_reserved = false;
-       h->sync = false;
        INIT_LIST_HEAD(&h->qgroup_ref_list);
        INIT_LIST_HEAD(&h->new_bgs);
-       INIT_LIST_HEAD(&h->ordered);
 
        smp_mb();
        if (cur_trans->state >= TRANS_STATE_BLOCKED &&
@@ -579,7 +565,6 @@ again:
                h->bytes_reserved = num_bytes;
                h->reloc_reserved = reloc_reserved;
        }
-       h->qgroup_reserved = qgroup_reserved;
 
 got_it:
        btrfs_record_root_in_trans(h, root);
@@ -597,20 +582,20 @@ alloc_fail:
                btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
                                        num_bytes);
 reserve_fail:
-       if (qgroup_reserved)
-               btrfs_qgroup_free(root, qgroup_reserved);
+       btrfs_qgroup_free_meta(root, qgroup_reserved);
        return ERR_PTR(ret);
 }
 
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
-                                                  int num_items)
+                                                  unsigned int num_items)
 {
        return start_transaction(root, num_items, TRANS_START,
                                 BTRFS_RESERVE_FLUSH_ALL);
 }
 
 struct btrfs_trans_handle *btrfs_start_transaction_lflush(
-                                       struct btrfs_root *root, int num_items)
+                                       struct btrfs_root *root,
+                                       unsigned int num_items)
 {
        return start_transaction(root, num_items, TRANS_START,
                                 BTRFS_RESERVE_FLUSH_LIMIT);
@@ -794,12 +779,6 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        if (!list_empty(&trans->new_bgs))
                btrfs_create_pending_block_groups(trans, root);
 
-       if (!list_empty(&trans->ordered)) {
-               spin_lock(&info->trans_lock);
-               list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
-               spin_unlock(&info->trans_lock);
-       }
-
        trans->delayed_ref_updates = 0;
        if (!trans->sync) {
                must_run_delayed_refs =
@@ -815,15 +794,6 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                        must_run_delayed_refs = 2;
        }
 
-       if (trans->qgroup_reserved) {
-               /*
-                * the same root has to be passed here between start_transaction
-                * and end_transaction. Subvolume quota depends on this.
-                */
-               btrfs_qgroup_free(trans->root, trans->qgroup_reserved);
-               trans->qgroup_reserved = 0;
-       }
-
        btrfs_trans_release_metadata(trans, root);
        trans->block_rsv = NULL;
 
@@ -856,6 +826,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        atomic_dec(&cur_trans->num_writers);
        extwriter_counter_dec(cur_trans, trans->type);
 
+       /*
+        * Make sure counter is updated before we wake up waiters.
+        */
        smp_mb();
        if (waitqueue_active(&cur_trans->writer_wait))
                wake_up(&cur_trans->writer_wait);
@@ -1238,6 +1211,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        spin_lock(&fs_info->fs_roots_radix_lock);
                        if (err)
                                break;
+                       btrfs_qgroup_free_meta_all(root);
                }
        }
        spin_unlock(&fs_info->fs_roots_radix_lock);
@@ -1795,25 +1769,10 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
 }
 
 static inline void
-btrfs_wait_pending_ordered(struct btrfs_transaction *cur_trans,
-                          struct btrfs_fs_info *fs_info)
+btrfs_wait_pending_ordered(struct btrfs_transaction *cur_trans)
 {
-       struct btrfs_ordered_extent *ordered;
-
-       spin_lock(&fs_info->trans_lock);
-       while (!list_empty(&cur_trans->pending_ordered)) {
-               ordered = list_first_entry(&cur_trans->pending_ordered,
-                                          struct btrfs_ordered_extent,
-                                          trans_list);
-               list_del_init(&ordered->trans_list);
-               spin_unlock(&fs_info->trans_lock);
-
-               wait_event(ordered->wait, test_bit(BTRFS_ORDERED_COMPLETE,
-                                                  &ordered->flags));
-               btrfs_put_ordered_extent(ordered);
-               spin_lock(&fs_info->trans_lock);
-       }
-       spin_unlock(&fs_info->trans_lock);
+       wait_event(cur_trans->pending_wait,
+                  atomic_read(&cur_trans->pending_ordered) == 0);
 }
 
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
@@ -1842,10 +1801,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_trans_release_metadata(trans, root);
        trans->block_rsv = NULL;
-       if (trans->qgroup_reserved) {
-               btrfs_qgroup_free(root, trans->qgroup_reserved);
-               trans->qgroup_reserved = 0;
-       }
 
        cur_trans = trans->transaction;
 
@@ -1865,7 +1820,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       if (!cur_trans->dirty_bg_run) {
+       if (!test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &cur_trans->flags)) {
                int run_it = 0;
 
                /* this mutex is also taken before trying to set
@@ -1874,18 +1829,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                 * after a extents from that block group have been
                 * allocated for cache files.  btrfs_set_block_group_ro
                 * will wait for the transaction to commit if it
-                * finds dirty_bg_run = 1
+                * finds BTRFS_TRANS_DIRTY_BG_RUN set.
                 *
-                * The dirty_bg_run flag is also used to make sure only
-                * one process starts all the block group IO.  It wouldn't
+                * The BTRFS_TRANS_DIRTY_BG_RUN flag is also used to make sure
+                * only one process starts all the block group IO.  It wouldn't
                 * hurt to have more than one go through, but there's no
                 * real advantage to it either.
                 */
                mutex_lock(&root->fs_info->ro_block_group_mutex);
-               if (!cur_trans->dirty_bg_run) {
+               if (!test_and_set_bit(BTRFS_TRANS_DIRTY_BG_RUN,
+                                     &cur_trans->flags))
                        run_it = 1;
-                       cur_trans->dirty_bg_run = 1;
-               }
                mutex_unlock(&root->fs_info->ro_block_group_mutex);
 
                if (run_it)
@@ -1897,7 +1851,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        }
 
        spin_lock(&root->fs_info->trans_lock);
-       list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                spin_unlock(&root->fs_info->trans_lock);
                atomic_inc(&cur_trans->use_count);
@@ -1956,7 +1909,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_wait_delalloc_flush(root->fs_info);
 
-       btrfs_wait_pending_ordered(cur_trans, root->fs_info);
+       btrfs_wait_pending_ordered(cur_trans);
 
        btrfs_scrub_pause(root);
        /*
@@ -2136,7 +2089,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        ret = btrfs_write_and_wait_transaction(trans, root);
        if (ret) {
-               btrfs_error(root->fs_info, ret,
+               btrfs_std_error(root->fs_info, ret,
                            "Error while writing out transaction");
                mutex_unlock(&root->fs_info->tree_log_mutex);
                goto scrub_continue;
@@ -2156,7 +2109,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_finish_extent_commit(trans, root);
 
-       if (cur_trans->have_free_bgs)
+       if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags))
                btrfs_clear_space_info_full(root->fs_info);
 
        root->fs_info->last_trans_committed = cur_trans->transid;
@@ -2198,10 +2151,6 @@ cleanup_transaction:
        btrfs_trans_release_metadata(trans, root);
        btrfs_trans_release_chunk_metadata(trans);
        trans->block_rsv = NULL;
-       if (trans->qgroup_reserved) {
-               btrfs_qgroup_free(root, trans->qgroup_reserved);
-               trans->qgroup_reserved = 0;
-       }
        btrfs_warn(root->fs_info, "Skipping commit of aborted transaction.");
        if (current->journal_info == trans)
                current->journal_info = NULL;
index a994bb097ee59c12bb0d5599f10c8a64b1954f43..b05b2f64d9133313f1af231c4a4254ff16972f00 100644 (file)
@@ -32,6 +32,10 @@ enum btrfs_trans_state {
        TRANS_STATE_MAX                 = 6,
 };
 
+#define BTRFS_TRANS_HAVE_FREE_BGS      0
+#define BTRFS_TRANS_DIRTY_BG_RUN       1
+#define BTRFS_TRANS_CACHE_ENOSPC       2
+
 struct btrfs_transaction {
        u64 transid;
        /*
@@ -46,11 +50,9 @@ struct btrfs_transaction {
         */
        atomic_t num_writers;
        atomic_t use_count;
+       atomic_t pending_ordered;
 
-       /*
-        * true if there is free bgs operations in this transaction
-        */
-       int have_free_bgs;
+       unsigned long flags;
 
        /* Be protected by fs_info->trans_lock when we want to change it. */
        enum btrfs_trans_state state;
@@ -59,9 +61,9 @@ struct btrfs_transaction {
        unsigned long start_time;
        wait_queue_head_t writer_wait;
        wait_queue_head_t commit_wait;
+       wait_queue_head_t pending_wait;
        struct list_head pending_snapshots;
        struct list_head pending_chunks;
-       struct list_head pending_ordered;
        struct list_head switch_commits;
        struct list_head dirty_bgs;
        struct list_head io_bgs;
@@ -80,7 +82,6 @@ struct btrfs_transaction {
        spinlock_t dropped_roots_lock;
        struct btrfs_delayed_ref_root delayed_refs;
        int aborted;
-       int dirty_bg_run;
 };
 
 #define __TRANS_FREEZABLE      (1U << 0)
@@ -107,7 +108,6 @@ struct btrfs_trans_handle {
        u64 transid;
        u64 bytes_reserved;
        u64 chunk_bytes_reserved;
-       u64 qgroup_reserved;
        unsigned long use_count;
        unsigned long blocks_reserved;
        unsigned long blocks_used;
@@ -129,7 +129,6 @@ struct btrfs_trans_handle {
         */
        struct btrfs_root *root;
        struct seq_list delayed_ref_elem;
-       struct list_head ordered;
        struct list_head qgroup_ref_list;
        struct list_head new_bgs;
 };
@@ -185,9 +184,10 @@ static inline void btrfs_clear_skip_qgroup(struct btrfs_trans_handle *trans)
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
-                                                  int num_items);
+                                                  unsigned int num_items);
 struct btrfs_trans_handle *btrfs_start_transaction_lflush(
-                                       struct btrfs_root *root, int num_items);
+                                       struct btrfs_root *root,
+                                       unsigned int num_items);
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root);
index 1bbaace733838e6fc70dba1babafb6f9265c00f9..323e12cc9d2f522388fe929ed66d4dd946b5881d 100644 (file)
@@ -229,7 +229,9 @@ int btrfs_pin_log_trans(struct btrfs_root *root)
 void btrfs_end_log_trans(struct btrfs_root *root)
 {
        if (atomic_dec_and_test(&root->log_writers)) {
-               smp_mb();
+               /*
+                * Implicit memory barrier after atomic_dec_and_test
+                */
                if (waitqueue_active(&root->log_writer_wait))
                        wake_up(&root->log_writer_wait);
        }
@@ -691,7 +693,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, 0);
+                                               key->objectid, offset);
                                if (ret)
                                        goto out;
                        } else {
@@ -2820,7 +2822,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        mutex_lock(&log_root_tree->log_mutex);
        if (atomic_dec_and_test(&log_root_tree->log_writers)) {
-               smp_mb();
+               /*
+                * Implicit memory barrier after atomic_dec_and_test
+                */
                if (waitqueue_active(&log_root_tree->log_writer_wait))
                        wake_up(&log_root_tree->log_writer_wait);
        }
@@ -2950,6 +2954,9 @@ out_wake_log_root:
        atomic_set(&log_root_tree->log_commit[index2], 0);
        mutex_unlock(&log_root_tree->log_mutex);
 
+       /*
+        * The barrier before waitqueue_active is implied by mutex_unlock
+        */
        if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
                wake_up(&log_root_tree->log_commit_wait[index2]);
 out:
@@ -2961,6 +2968,9 @@ out:
        atomic_set(&root->log_commit[index1], 0);
        mutex_unlock(&root->log_mutex);
 
+       /*
+        * The barrier before waitqueue_active is implied by mutex_unlock
+        */
        if (waitqueue_active(&root->log_commit_wait[index1]))
                wake_up(&root->log_commit_wait[index1]);
        return ret;
@@ -5314,7 +5324,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 
        ret = walk_log_tree(trans, log_root_tree, &wc);
        if (ret) {
-               btrfs_error(fs_info, ret, "Failed to pin buffers while "
+               btrfs_std_error(fs_info, ret, "Failed to pin buffers while "
                            "recovering log root tree.");
                goto error;
        }
@@ -5328,7 +5338,7 @@ again:
                ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
 
                if (ret < 0) {
-                       btrfs_error(fs_info, ret,
+                       btrfs_std_error(fs_info, ret,
                                    "Couldn't find tree log root.");
                        goto error;
                }
@@ -5346,7 +5356,7 @@ again:
                log = btrfs_read_fs_root(log_root_tree, &found_key);
                if (IS_ERR(log)) {
                        ret = PTR_ERR(log);
-                       btrfs_error(fs_info, ret,
+                       btrfs_std_error(fs_info, ret,
                                    "Couldn't read tree log root.");
                        goto error;
                }
@@ -5361,7 +5371,7 @@ again:
                        free_extent_buffer(log->node);
                        free_extent_buffer(log->commit_root);
                        kfree(log);
-                       btrfs_error(fs_info, ret, "Couldn't read target root "
+                       btrfs_std_error(fs_info, ret, "Couldn't read target root "
                                    "for tree log recovery.");
                        goto error;
                }
index e023919b447064cbc6fad6984065731cbbde68c3..9b2dafa5ba59178644c6c01879583cc2769a52e8 100644 (file)
 #include "dev-replace.h"
 #include "sysfs.h"
 
+const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
+       [BTRFS_RAID_RAID10] = {
+               .sub_stripes    = 2,
+               .dev_stripes    = 1,
+               .devs_max       = 0,    /* 0 == as many as possible */
+               .devs_min       = 4,
+               .tolerated_failures = 1,
+               .devs_increment = 2,
+               .ncopies        = 2,
+       },
+       [BTRFS_RAID_RAID1] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 1,
+               .devs_max       = 2,
+               .devs_min       = 2,
+               .tolerated_failures = 1,
+               .devs_increment = 2,
+               .ncopies        = 2,
+       },
+       [BTRFS_RAID_DUP] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 2,
+               .devs_max       = 1,
+               .devs_min       = 1,
+               .tolerated_failures = 0,
+               .devs_increment = 1,
+               .ncopies        = 2,
+       },
+       [BTRFS_RAID_RAID0] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 1,
+               .devs_max       = 0,
+               .devs_min       = 2,
+               .tolerated_failures = 0,
+               .devs_increment = 1,
+               .ncopies        = 1,
+       },
+       [BTRFS_RAID_SINGLE] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 1,
+               .devs_max       = 1,
+               .devs_min       = 1,
+               .tolerated_failures = 0,
+               .devs_increment = 1,
+               .ncopies        = 1,
+       },
+       [BTRFS_RAID_RAID5] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 1,
+               .devs_max       = 0,
+               .devs_min       = 2,
+               .tolerated_failures = 1,
+               .devs_increment = 1,
+               .ncopies        = 2,
+       },
+       [BTRFS_RAID_RAID6] = {
+               .sub_stripes    = 1,
+               .dev_stripes    = 1,
+               .devs_max       = 0,
+               .devs_min       = 3,
+               .tolerated_failures = 2,
+               .devs_increment = 1,
+               .ncopies        = 3,
+       },
+};
+
+const u64 const btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
+       [BTRFS_RAID_RAID10] = BTRFS_BLOCK_GROUP_RAID10,
+       [BTRFS_RAID_RAID1]  = BTRFS_BLOCK_GROUP_RAID1,
+       [BTRFS_RAID_DUP]    = BTRFS_BLOCK_GROUP_DUP,
+       [BTRFS_RAID_RAID0]  = BTRFS_BLOCK_GROUP_RAID0,
+       [BTRFS_RAID_SINGLE] = 0,
+       [BTRFS_RAID_RAID5]  = BTRFS_BLOCK_GROUP_RAID5,
+       [BTRFS_RAID_RAID6]  = BTRFS_BLOCK_GROUP_RAID6,
+};
+
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                struct btrfs_device *device);
@@ -198,7 +274,6 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
 
        if (IS_ERR(*bdev)) {
                ret = PTR_ERR(*bdev);
-               printk(KERN_INFO "BTRFS: open %s failed\n", device_path);
                goto error;
        }
 
@@ -211,8 +286,8 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
        }
        invalidate_bdev(*bdev);
        *bh = btrfs_read_dev_super(*bdev);
-       if (!*bh) {
-               ret = -EINVAL;
+       if (IS_ERR(*bh)) {
+               ret = PTR_ERR(*bh);
                blkdev_put(*bdev, flags);
                goto error;
        }
@@ -345,6 +420,9 @@ loop_lock:
                pending = pending->bi_next;
                cur->bi_next = NULL;
 
+               /*
+                * atomic_dec_return implies a barrier for waitqueue_active
+                */
                if (atomic_dec_return(&fs_info->nr_async_bios) < limit &&
                    waitqueue_active(&fs_info->async_submit_wait))
                        wake_up(&fs_info->async_submit_wait);
@@ -765,36 +843,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) {
-               struct btrfs_device *new_device;
-               struct rcu_string *name;
-
-               if (device->bdev)
-                       fs_devices->open_devices--;
-
-               if (device->writeable &&
-                   device->devid != BTRFS_DEV_REPLACE_DEVID) {
-                       list_del_init(&device->dev_alloc_list);
-                       fs_devices->rw_devices--;
-               }
-
-               if (device->missing)
-                       fs_devices->missing_devices--;
-
-               new_device = btrfs_alloc_device(NULL, &device->devid,
-                                               device->uuid);
-               BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
-
-               /* Safe because we are under uuid_mutex */
-               if (device->name) {
-                       name = rcu_string_strdup(device->name->str, GFP_NOFS);
-                       BUG_ON(!name); /* -ENOMEM */
-                       rcu_assign_pointer(new_device->name, name);
-               }
-
-               list_replace_rcu(&device->dev_list, &new_device->dev_list);
-               new_device->fs_devices = device->fs_devices;
-
-               call_rcu(&device->rcu, free_device);
+               btrfs_close_one_device(device);
        }
        mutex_unlock(&fs_devices->device_list_mutex);
 
@@ -1402,7 +1451,7 @@ again:
                extent = btrfs_item_ptr(leaf, path->slots[0],
                                        struct btrfs_dev_extent);
        } else {
-               btrfs_error(root->fs_info, ret, "Slot search failed");
+               btrfs_std_error(root->fs_info, ret, "Slot search failed");
                goto out;
        }
 
@@ -1410,10 +1459,10 @@ again:
 
        ret = btrfs_del_item(trans, root, path);
        if (ret) {
-               btrfs_error(root->fs_info, ret,
+               btrfs_std_error(root->fs_info, ret,
                            "Failed to remove dev extent item");
        } else {
-               trans->transaction->have_free_bgs = 1;
+               set_bit(BTRFS_TRANS_HAVE_FREE_BGS, &trans->transaction->flags);
        }
 out:
        btrfs_free_path(path);
@@ -1801,7 +1850,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        if (device->bdev) {
                device->fs_devices->open_devices--;
                /* remove sysfs entry */
-               btrfs_kobj_rm_device(root->fs_info->fs_devices, device);
+               btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device);
        }
 
        call_rcu(&device->rcu, free_device);
@@ -1924,7 +1973,8 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
        if (srcdev->writeable) {
                fs_devices->rw_devices--;
                /* zero out the old super if it is writable */
-               btrfs_scratch_superblock(srcdev);
+               btrfs_scratch_superblocks(srcdev->bdev,
+                                       rcu_str_deref(srcdev->name));
        }
 
        if (srcdev->bdev)
@@ -1971,10 +2021,11 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        WARN_ON(!tgtdev);
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
 
-       btrfs_kobj_rm_device(fs_info->fs_devices, tgtdev);
+       btrfs_sysfs_rm_device_link(fs_info->fs_devices, tgtdev);
 
        if (tgtdev->bdev) {
-               btrfs_scratch_superblock(tgtdev);
+               btrfs_scratch_superblocks(tgtdev->bdev,
+                                       rcu_str_deref(tgtdev->name));
                fs_info->fs_devices->open_devices--;
        }
        fs_info->fs_devices->num_devices--;
@@ -2041,10 +2092,8 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
                        }
                }
 
-               if (!*device) {
-                       btrfs_err(root->fs_info, "no missing device found");
-                       return -ENOENT;
-               }
+               if (!*device)
+                       return BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
 
                return 0;
        } else {
@@ -2309,7 +2358,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                                    tmp + 1);
 
        /* add sysfs device entry */
-       btrfs_kobj_add_device(root->fs_info->fs_devices, device);
+       btrfs_sysfs_add_device_link(root->fs_info->fs_devices, device);
 
        /*
         * we've got more storage, clear any full flags on the space
@@ -2350,9 +2399,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                 */
                snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU",
                                                root->fs_info->fsid);
-               if (kobject_rename(&root->fs_info->fs_devices->super_kobj,
+               if (kobject_rename(&root->fs_info->fs_devices->fsid_kobj,
                                                                fsid_buf))
-                       pr_warn("BTRFS: sysfs: failed to create fsid for sprout\n");
+                       btrfs_warn(root->fs_info,
+                               "sysfs: failed to create fsid for sprout");
        }
 
        root->fs_info->num_tolerated_disk_barrier_failures =
@@ -2368,7 +2418,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
                ret = btrfs_relocate_sys_chunks(root);
                if (ret < 0)
-                       btrfs_error(root->fs_info, ret,
+                       btrfs_std_error(root->fs_info, ret,
                                    "Failed to relocate sys chunks after "
                                    "device initialization. This can be fixed "
                                    "using the \"btrfs balance\" command.");
@@ -2388,7 +2438,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 error_trans:
        btrfs_end_transaction(trans, root);
        rcu_string_free(device->name);
-       btrfs_kobj_rm_device(root->fs_info->fs_devices, device);
+       btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device);
        kfree(device);
 error:
        blkdev_put(bdev, FMODE_EXCL);
@@ -2613,7 +2663,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
        if (ret < 0)
                goto out;
        else if (ret > 0) { /* Logic error or corruption */
-               btrfs_error(root->fs_info, -ENOENT,
+               btrfs_std_error(root->fs_info, -ENOENT,
                            "Failed lookup while freeing chunk.");
                ret = -ENOENT;
                goto out;
@@ -2621,7 +2671,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
 
        ret = btrfs_del_item(trans, root, path);
        if (ret < 0)
-               btrfs_error(root->fs_info, ret,
+               btrfs_std_error(root->fs_info, ret,
                            "Failed to delete chunk item.");
 out:
        btrfs_free_path(path);
@@ -2806,7 +2856,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
-               btrfs_std_error(root->fs_info, ret);
+               btrfs_std_error(root->fs_info, ret, NULL);
                return ret;
        }
 
@@ -3009,16 +3059,19 @@ static void update_balance_args(struct btrfs_balance_control *bctl)
         * (albeit full) chunks.
         */
        if (!(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+           !(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
            !(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_USAGE_RANGE) &&
            !(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_USAGE_RANGE) &&
            !(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
                bctl->meta.flags |= BTRFS_BALANCE_ARGS_USAGE;
                bctl->meta.usage = 90;
@@ -3072,6 +3125,39 @@ static int chunk_profiles_filter(u64 chunk_type,
 
 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;
+       u64 user_thresh_min;
+       u64 user_thresh_max;
+       int ret = 1;
+
+       cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+       chunk_used = btrfs_block_group_used(&cache->item);
+
+       if (bargs->usage_min == 0)
+               user_thresh_min = 0;
+       else
+               user_thresh_min = div_factor_fine(cache->key.offset,
+                                       bargs->usage_min);
+
+       if (bargs->usage_max == 0)
+               user_thresh_max = 1;
+       else if (bargs->usage_max > 100)
+               user_thresh_max = cache->key.offset;
+       else
+               user_thresh_max = div_factor_fine(cache->key.offset,
+                                       bargs->usage_max);
+
+       if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max)
+               ret = 0;
+
+       btrfs_put_block_group(cache);
+       return ret;
+}
+
+static int chunk_usage_range_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;
@@ -3080,7 +3166,7 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
        cache = btrfs_lookup_block_group(fs_info, chunk_offset);
        chunk_used = btrfs_block_group_used(&cache->item);
 
-       if (bargs->usage == 0)
+       if (bargs->usage_min == 0)
                user_thresh = 1;
        else if (bargs->usage > 100)
                user_thresh = cache->key.offset;
@@ -3170,6 +3256,19 @@ static int chunk_vrange_filter(struct extent_buffer *leaf,
        return 1;
 }
 
+static int chunk_stripes_range_filter(struct extent_buffer *leaf,
+                              struct btrfs_chunk *chunk,
+                              struct btrfs_balance_args *bargs)
+{
+       int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+
+       if (bargs->stripes_min <= num_stripes
+                       && num_stripes <= bargs->stripes_max)
+               return 0;
+
+       return 1;
+}
+
 static int chunk_soft_convert_filter(u64 chunk_type,
                                     struct btrfs_balance_args *bargs)
 {
@@ -3216,6 +3315,9 @@ static int should_balance_chunk(struct btrfs_root *root,
        if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) &&
            chunk_usage_filter(bctl->fs_info, chunk_offset, bargs)) {
                return 0;
+       } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
+           chunk_usage_range_filter(bctl->fs_info, chunk_offset, bargs)) {
+               return 0;
        }
 
        /* devid filter */
@@ -3236,6 +3338,12 @@ static int should_balance_chunk(struct btrfs_root *root,
                return 0;
        }
 
+       /* stripes filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) &&
+           chunk_stripes_range_filter(leaf, chunk, bargs)) {
+               return 0;
+       }
+
        /* soft profile changing mode */
        if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) &&
            chunk_soft_convert_filter(chunk_type, bargs)) {
@@ -3250,6 +3358,16 @@ static int should_balance_chunk(struct btrfs_root *root,
                        return 0;
                else
                        bargs->limit--;
+       } else if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE)) {
+               /*
+                * Same logic as the 'limit' filter; the minimum cannot be
+                * determined here because we do not have the global informatoin
+                * about the count of all chunks that satisfy the filters.
+                */
+               if (bargs->limit_max == 0)
+                       return 0;
+               else
+                       bargs->limit_max--;
        }
 
        return 1;
@@ -3264,6 +3382,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
        struct btrfs_device *device;
        u64 old_size;
        u64 size_to_free;
+       u64 chunk_type;
        struct btrfs_chunk *chunk;
        struct btrfs_path *path;
        struct btrfs_key key;
@@ -3274,9 +3393,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
        int ret;
        int enospc_errors = 0;
        bool counting = true;
+       /* The single value limit and min/max limits use the same bytes in the */
        u64 limit_data = bctl->data.limit;
        u64 limit_meta = bctl->meta.limit;
        u64 limit_sys = bctl->sys.limit;
+       u32 count_data = 0;
+       u32 count_meta = 0;
+       u32 count_sys = 0;
 
        /* step one make some room on all the devices */
        devices = &fs_info->fs_devices->devices;
@@ -3317,6 +3440,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
        spin_unlock(&fs_info->balance_lock);
 again:
        if (!counting) {
+               /*
+                * The single value limit and min/max limits use the same bytes
+                * in the
+                */
                bctl->data.limit = limit_data;
                bctl->meta.limit = limit_meta;
                bctl->sys.limit = limit_sys;
@@ -3364,6 +3491,7 @@ again:
                }
 
                chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
+               chunk_type = btrfs_chunk_type(leaf, chunk);
 
                if (!counting) {
                        spin_lock(&fs_info->balance_lock);
@@ -3384,6 +3512,28 @@ again:
                        spin_lock(&fs_info->balance_lock);
                        bctl->stat.expected++;
                        spin_unlock(&fs_info->balance_lock);
+
+                       if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
+                               count_data++;
+                       else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM)
+                               count_sys++;
+                       else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA)
+                               count_meta++;
+
+                       goto loop;
+               }
+
+               /*
+                * Apply limit_min filter, no need to check if the LIMITS
+                * filter is used, limit_min is 0 by default
+                */
+               if (((chunk_type & BTRFS_BLOCK_GROUP_DATA) &&
+                                       count_data < bctl->data.limit_min)
+                               || ((chunk_type & BTRFS_BLOCK_GROUP_METADATA) &&
+                                       count_meta < bctl->meta.limit_min)
+                               || ((chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) &&
+                                       count_sys < bctl->sys.limit_min)) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        goto loop;
                }
 
@@ -3461,11 +3611,20 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)
        unset_balance_control(fs_info);
        ret = del_balance_item(fs_info->tree_root);
        if (ret)
-               btrfs_std_error(fs_info, ret);
+               btrfs_std_error(fs_info, ret, NULL);
 
        atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
 }
 
+/* Non-zero return value signifies invalidity */
+static inline int validate_convert_profile(struct btrfs_balance_args *bctl_arg,
+               u64 allowed)
+{
+       return ((bctl_arg->flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+               (!alloc_profile_is_valid(bctl_arg->target, 1) ||
+                (bctl_arg->target & ~allowed)));
+}
+
 /*
  * Should be called with both balance and volume mutexes held
  */
@@ -3523,27 +3682,21 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        if (num_devices > 3)
                allowed |= (BTRFS_BLOCK_GROUP_RAID10 |
                            BTRFS_BLOCK_GROUP_RAID6);
-       if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-           (!alloc_profile_is_valid(bctl->data.target, 1) ||
-            (bctl->data.target & ~allowed))) {
+       if (validate_convert_profile(&bctl->data, allowed)) {
                btrfs_err(fs_info, "unable to start balance with target "
                           "data profile %llu",
                       bctl->data.target);
                ret = -EINVAL;
                goto out;
        }
-       if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-           (!alloc_profile_is_valid(bctl->meta.target, 1) ||
-            (bctl->meta.target & ~allowed))) {
+       if (validate_convert_profile(&bctl->meta, allowed)) {
                btrfs_err(fs_info,
                           "unable to start balance with target metadata profile %llu",
                       bctl->meta.target);
                ret = -EINVAL;
                goto out;
        }
-       if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-           (!alloc_profile_is_valid(bctl->sys.target, 1) ||
-            (bctl->sys.target & ~allowed))) {
+       if (validate_convert_profile(&bctl->sys, allowed)) {
                btrfs_err(fs_info,
                           "unable to start balance with target system profile %llu",
                       bctl->sys.target);
@@ -4285,65 +4438,6 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
        return 0;
 }
 
-static const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
-       [BTRFS_RAID_RAID10] = {
-               .sub_stripes    = 2,
-               .dev_stripes    = 1,
-               .devs_max       = 0,    /* 0 == as many as possible */
-               .devs_min       = 4,
-               .devs_increment = 2,
-               .ncopies        = 2,
-       },
-       [BTRFS_RAID_RAID1] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 1,
-               .devs_max       = 2,
-               .devs_min       = 2,
-               .devs_increment = 2,
-               .ncopies        = 2,
-       },
-       [BTRFS_RAID_DUP] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 2,
-               .devs_max       = 1,
-               .devs_min       = 1,
-               .devs_increment = 1,
-               .ncopies        = 2,
-       },
-       [BTRFS_RAID_RAID0] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 1,
-               .devs_max       = 0,
-               .devs_min       = 2,
-               .devs_increment = 1,
-               .ncopies        = 1,
-       },
-       [BTRFS_RAID_SINGLE] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 1,
-               .devs_max       = 1,
-               .devs_min       = 1,
-               .devs_increment = 1,
-               .ncopies        = 1,
-       },
-       [BTRFS_RAID_RAID5] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 1,
-               .devs_max       = 0,
-               .devs_min       = 2,
-               .devs_increment = 1,
-               .ncopies        = 2,
-       },
-       [BTRFS_RAID_RAID6] = {
-               .sub_stripes    = 1,
-               .dev_stripes    = 1,
-               .devs_max       = 0,
-               .devs_min       = 3,
-               .devs_increment = 1,
-               .ncopies        = 3,
-       },
-};
-
 static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target)
 {
        /* TODO allow them to set a preferred stripe size */
@@ -6594,8 +6688,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
        BUG_ON(!path);
        ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
        if (ret < 0) {
-               printk_in_rcu(KERN_WARNING "BTRFS: "
-                       "error %d while searching for dev_stats item for device %s!\n",
+               btrfs_warn_in_rcu(dev_root->fs_info,
+                       "error %d while searching for dev_stats item for device %s",
                              ret, rcu_str_deref(device->name));
                goto out;
        }
@@ -6605,8 +6699,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
                /* need to delete old one and insert a new one */
                ret = btrfs_del_item(trans, dev_root, path);
                if (ret != 0) {
-                       printk_in_rcu(KERN_WARNING "BTRFS: "
-                               "delete too small dev_stats item for device %s failed %d!\n",
+                       btrfs_warn_in_rcu(dev_root->fs_info,
+                               "delete too small dev_stats item for device %s failed %d",
                                      rcu_str_deref(device->name), ret);
                        goto out;
                }
@@ -6619,9 +6713,9 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
                ret = btrfs_insert_empty_item(trans, dev_root, path,
                                              &key, sizeof(*ptr));
                if (ret < 0) {
-                       printk_in_rcu(KERN_WARNING "BTRFS: "
-                                         "insert dev_stats item for device %s failed %d!\n",
-                                     rcu_str_deref(device->name), ret);
+                       btrfs_warn_in_rcu(dev_root->fs_info,
+                               "insert dev_stats item for device %s failed %d",
+                               rcu_str_deref(device->name), ret);
                        goto out;
                }
        }
@@ -6675,8 +6769,8 @@ static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)
 {
        if (!dev->dev_stats_valid)
                return;
-       printk_ratelimited_in_rcu(KERN_ERR "BTRFS: "
-                          "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
+       btrfs_err_rl_in_rcu(dev->dev_root->fs_info,
+               "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u",
                           rcu_str_deref(dev->name),
                           btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
                           btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
@@ -6695,8 +6789,8 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
        if (i == BTRFS_DEV_STAT_VALUES_MAX)
                return; /* all values == 0, suppress message */
 
-       printk_in_rcu(KERN_INFO "BTRFS: "
-                  "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
+       btrfs_info_in_rcu(dev->dev_root->fs_info,
+               "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u",
               rcu_str_deref(dev->name),
               btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
               btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
@@ -6740,22 +6834,34 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
        return 0;
 }
 
-int btrfs_scratch_superblock(struct btrfs_device *device)
+void btrfs_scratch_superblocks(struct block_device *bdev, char *device_path)
 {
        struct buffer_head *bh;
        struct btrfs_super_block *disk_super;
+       int copy_num;
 
-       bh = btrfs_read_dev_super(device->bdev);
-       if (!bh)
-               return -EINVAL;
-       disk_super = (struct btrfs_super_block *)bh->b_data;
+       if (!bdev)
+               return;
 
-       memset(&disk_super->magic, 0, sizeof(disk_super->magic));
-       set_buffer_dirty(bh);
-       sync_dirty_buffer(bh);
-       brelse(bh);
+       for (copy_num = 0; copy_num < BTRFS_SUPER_MIRROR_MAX;
+               copy_num++) {
 
-       return 0;
+               if (btrfs_read_dev_one_super(bdev, copy_num, &bh))
+                       continue;
+
+               disk_super = (struct btrfs_super_block *)bh->b_data;
+
+               memset(&disk_super->magic, 0, sizeof(disk_super->magic));
+               set_buffer_dirty(bh);
+               sync_dirty_buffer(bh);
+               brelse(bh);
+       }
+
+       /* Notify udev that device has changed */
+       btrfs_kobject_uevent(bdev, KOBJ_CHANGE);
+
+       /* Update ctime/mtime for device path for libblkid */
+       update_dev_time(device_path);
 }
 
 /*
@@ -6823,3 +6929,38 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info)
                fs_devices = fs_devices->seed;
        }
 }
+
+void btrfs_close_one_device(struct btrfs_device *device)
+{
+       struct btrfs_fs_devices *fs_devices = device->fs_devices;
+       struct btrfs_device *new_device;
+       struct rcu_string *name;
+
+       if (device->bdev)
+               fs_devices->open_devices--;
+
+       if (device->writeable &&
+           device->devid != BTRFS_DEV_REPLACE_DEVID) {
+               list_del_init(&device->dev_alloc_list);
+               fs_devices->rw_devices--;
+       }
+
+       if (device->missing)
+               fs_devices->missing_devices--;
+
+       new_device = btrfs_alloc_device(NULL, &device->devid,
+                                       device->uuid);
+       BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
+
+       /* Safe because we are under uuid_mutex */
+       if (device->name) {
+               name = rcu_string_strdup(device->name->str, GFP_NOFS);
+               BUG_ON(!name); /* -ENOMEM */
+               rcu_assign_pointer(new_device->name, name);
+       }
+
+       list_replace_rcu(&device->dev_list, &new_device->dev_list);
+       new_device->fs_devices = device->fs_devices;
+
+       call_rcu(&device->rcu, free_device);
+}
index 595279a8b99fd461e24cb24df3805fa8401f3dd6..ec571237273208fcb87f7be1c473b0c6a1392b50 100644 (file)
@@ -256,7 +256,7 @@ struct btrfs_fs_devices {
 
        struct btrfs_fs_info *fs_info;
        /* sysfs kobjects */
-       struct kobject super_kobj;
+       struct kobject fsid_kobj;
        struct kobject *device_dir_kobj;
        struct completion kobj_unregister;
 };
@@ -334,10 +334,15 @@ struct btrfs_raid_attr {
        int dev_stripes;        /* stripes per dev */
        int devs_max;           /* max devs to use */
        int devs_min;           /* min devs needed */
+       int tolerated_failures; /* max tolerated fail devs */
        int devs_increment;     /* ndevs has to be a multiple of this */
        int ncopies;            /* how many copies to data has */
 };
 
+extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES];
+
+extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES];
+
 struct map_lookup {
        u64 type;
        int io_align;
@@ -375,6 +380,9 @@ struct map_lookup {
 #define BTRFS_BALANCE_ARGS_DRANGE      (1ULL << 3)
 #define BTRFS_BALANCE_ARGS_VRANGE      (1ULL << 4)
 #define BTRFS_BALANCE_ARGS_LIMIT       (1ULL << 5)
+#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
+#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
+#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 8)
 
 #define BTRFS_BALANCE_ARGS_MASK                        \
        (BTRFS_BALANCE_ARGS_PROFILES |          \
@@ -382,7 +390,10 @@ struct map_lookup {
         BTRFS_BALANCE_ARGS_DEVID |             \
         BTRFS_BALANCE_ARGS_DRANGE |            \
         BTRFS_BALANCE_ARGS_VRANGE |            \
-        BTRFS_BALANCE_ARGS_LIMIT)
+        BTRFS_BALANCE_ARGS_LIMIT |             \
+        BTRFS_BALANCE_ARGS_LIMIT_RANGE |       \
+        BTRFS_BALANCE_ARGS_STRIPES_RANGE |     \
+        BTRFS_BALANCE_ARGS_USAGE_RANGE)
 
 /*
  * Profile changing flags.  When SOFT is set we won't relocate chunk if
@@ -482,7 +493,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
                                      struct btrfs_device *tgtdev);
 void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
                                              struct btrfs_device *tgtdev);
-int btrfs_scratch_superblock(struct btrfs_device *device);
+void btrfs_scratch_superblocks(struct block_device *bdev, char *device_path);
 int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree,
                           u64 logical, u64 len, int mirror_num);
 unsigned long btrfs_full_stripe_len(struct btrfs_root *root,
@@ -555,5 +566,6 @@ static inline void unlock_chunks(struct btrfs_root *root)
 struct list_head *btrfs_get_fs_uuids(void);
 void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
 void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
+void btrfs_close_one_device(struct btrfs_device *device);
 
 #endif
index b1eede3678a91d8d1ea3e350cb035cabf1da7ba7..0557c45e9c3308a368f7ff3e73f9423c81eedea4 100644 (file)
@@ -84,7 +84,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
        cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
 
        dentry = d_hash_and_lookup(parent, name);
-       if (unlikely(IS_ERR(dentry)))
+       if (IS_ERR(dentry))
                return;
 
        if (dentry) {
index 3c4db1172d222840b8cf0fcd50a61437ebf5f4c7..e2e47ba5d313a5f2aca58589e08d2d3df969bed2 100644 (file)
@@ -270,7 +270,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
 
        ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry,
                                            mode);
-       if (unlikely(IS_ERR(ecryptfs_inode))) {
+       if (IS_ERR(ecryptfs_inode)) {
                ecryptfs_printk(KERN_WARNING, "Failed to create file in"
                                "lower filesystem\n");
                rc = PTR_ERR(ecryptfs_inode);
index 75285ea9aa05a68cde3830c67c027ef1e4fcdcde..f52cf54f0cbc4ceb6c236a4d4ae404a3282cd0a0 100644 (file)
@@ -8,7 +8,7 @@ ext4-y  := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
                ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
                ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
                mmp.o indirect.o extents_status.o xattr.o xattr_user.o \
-               xattr_trusted.o inline.o readpage.o
+               xattr_trusted.o inline.o readpage.o sysfs.o
 
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
 ext4-$(CONFIG_EXT4_FS_SECURITY)                += xattr_security.o
index cd6ea29be6457b52b442ec0a159e5732fad9563f..ec0668a60678d215dadc9baa97623ddbd3dbc160 100644 (file)
@@ -191,6 +191,7 @@ static int ext4_init_block_bitmap(struct super_block *sb,
        /* If checksum is bad mark all blocks used to prevent allocation
         * essentially implementing a per-group read-only flag. */
        if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
+               ext4_error(sb, "Checksum bad for group %u", block_group);
                grp = ext4_get_group_info(sb, block_group);
                if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
                        percpu_counter_sub(&sbi->s_freeclusters_counter,
@@ -203,7 +204,7 @@ static int ext4_init_block_bitmap(struct super_block *sb,
                                           count);
                }
                set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return -EIO;
+               return -EFSBADCRC;
        }
        memset(bh->b_data, 0, sb->s_blocksize);
 
@@ -213,7 +214,7 @@ static int ext4_init_block_bitmap(struct super_block *sb,
 
        start = ext4_group_first_block_no(sb, block_group);
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+       if (ext4_has_feature_flex_bg(sb))
                flex_bg = 1;
 
        /* Set bits for block and inode bitmaps, and inode table */
@@ -322,7 +323,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
        ext4_fsblk_t blk;
        ext4_fsblk_t group_first_block;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+       if (ext4_has_feature_flex_bg(sb)) {
                /* with FLEX_BG, the inode/block bitmaps and itable
                 * blocks may not be in the group at all
                 * so the bitmap validation will be skipped for those groups
@@ -360,42 +361,45 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
        return 0;
 }
 
-static void ext4_validate_block_bitmap(struct super_block *sb,
-                                      struct ext4_group_desc *desc,
-                                      ext4_group_t block_group,
-                                      struct buffer_head *bh)
+static int ext4_validate_block_bitmap(struct super_block *sb,
+                                     struct ext4_group_desc *desc,
+                                     ext4_group_t block_group,
+                                     struct buffer_head *bh)
 {
        ext4_fsblk_t    blk;
        struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       if (buffer_verified(bh) || EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
-               return;
+       if (buffer_verified(bh))
+               return 0;
+       if (EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
+               return -EFSCORRUPTED;
 
        ext4_lock_group(sb, block_group);
-       blk = ext4_valid_block_bitmap(sb, desc, block_group, bh);
-       if (unlikely(blk != 0)) {
+       if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
+                       desc, bh))) {
                ext4_unlock_group(sb, block_group);
-               ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
-                          block_group, blk);
+               ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
                if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
                        percpu_counter_sub(&sbi->s_freeclusters_counter,
                                           grp->bb_free);
                set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return;
+               return -EFSBADCRC;
        }
-       if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
-                       desc, bh))) {
+       blk = ext4_valid_block_bitmap(sb, desc, block_group, bh);
+       if (unlikely(blk != 0)) {
                ext4_unlock_group(sb, block_group);
-               ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
+               ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
+                          block_group, blk);
                if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
                        percpu_counter_sub(&sbi->s_freeclusters_counter,
                                           grp->bb_free);
                set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return;
+               return -EFSCORRUPTED;
        }
        set_buffer_verified(bh);
        ext4_unlock_group(sb, block_group);
+       return 0;
 }
 
 /**
@@ -414,17 +418,18 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
        struct ext4_group_desc *desc;
        struct buffer_head *bh;
        ext4_fsblk_t bitmap_blk;
+       int err;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               return NULL;
+               return ERR_PTR(-EFSCORRUPTED);
        bitmap_blk = ext4_block_bitmap(sb, desc);
        bh = sb_getblk(sb, bitmap_blk);
        if (unlikely(!bh)) {
                ext4_error(sb, "Cannot get buffer for block bitmap - "
                           "block_group = %u, block_bitmap = %llu",
                           block_group, bitmap_blk);
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
        if (bitmap_uptodate(bh))
@@ -437,7 +442,6 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
        }
        ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-               int err;
 
                err = ext4_init_block_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
@@ -445,7 +449,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
                if (err)
-                       ext4_error(sb, "Checksum bad for grp %u", block_group);
+                       goto out;
                goto verify;
        }
        ext4_unlock_group(sb, block_group);
@@ -468,11 +472,13 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
        submit_bh(READ | REQ_META | REQ_PRIO, bh);
        return bh;
 verify:
-       ext4_validate_block_bitmap(sb, desc, block_group, bh);
-       if (buffer_verified(bh))
-               return bh;
+       err = ext4_validate_block_bitmap(sb, desc, block_group, bh);
+       if (err)
+               goto out;
+       return bh;
+out:
        put_bh(bh);
-       return NULL;
+       return ERR_PTR(err);
 }
 
 /* Returns 0 on success, 1 on error */
@@ -485,32 +491,32 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
                return 0;
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               return 1;
+               return -EFSCORRUPTED;
        wait_on_buffer(bh);
        if (!buffer_uptodate(bh)) {
                ext4_error(sb, "Cannot read block bitmap - "
                           "block_group = %u, block_bitmap = %llu",
                           block_group, (unsigned long long) bh->b_blocknr);
-               return 1;
+               return -EIO;
        }
        clear_buffer_new(bh);
        /* Panic or remount fs read-only if block bitmap is invalid */
-       ext4_validate_block_bitmap(sb, desc, block_group, bh);
-       /* ...but check for error just in case errors=continue. */
-       return !buffer_verified(bh);
+       return ext4_validate_block_bitmap(sb, desc, block_group, bh);
 }
 
 struct buffer_head *
 ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
        struct buffer_head *bh;
+       int err;
 
        bh = ext4_read_block_bitmap_nowait(sb, block_group);
-       if (!bh)
-               return NULL;
-       if (ext4_wait_block_bitmap(sb, block_group, bh)) {
+       if (IS_ERR(bh))
+               return bh;
+       err = ext4_wait_block_bitmap(sb, block_group, bh);
+       if (err) {
                put_bh(bh);
-               return NULL;
+               return ERR_PTR(err);
        }
        return bh;
 }
@@ -681,8 +687,10 @@ ext4_fsblk_t ext4_count_free_clusters(struct super_block *sb)
                        desc_count += ext4_free_group_clusters(sb, gdp);
                brelse(bitmap_bh);
                bitmap_bh = ext4_read_block_bitmap(sb, i);
-               if (bitmap_bh == NULL)
+               if (IS_ERR(bitmap_bh)) {
+                       bitmap_bh = NULL;
                        continue;
+               }
 
                x = ext4_count_free(bitmap_bh->b_data,
                                    EXT4_CLUSTERS_PER_GROUP(sb) / 8);
@@ -740,14 +748,13 @@ int ext4_bg_has_super(struct super_block *sb, ext4_group_t group)
 
        if (group == 0)
                return 1;
-       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
+       if (ext4_has_feature_sparse_super2(sb)) {
                if (group == le32_to_cpu(es->s_backup_bgs[0]) ||
                    group == le32_to_cpu(es->s_backup_bgs[1]))
                        return 1;
                return 0;
        }
-       if ((group <= 1) || !EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
+       if ((group <= 1) || !ext4_has_feature_sparse_super(sb))
                return 1;
        if (!(group & 1))
                return 0;
@@ -776,7 +783,7 @@ static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
        if (!ext4_bg_has_super(sb, group))
                return 0;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG))
+       if (ext4_has_feature_meta_bg(sb))
                return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
        else
                return EXT4_SB(sb)->s_gdb_count;
@@ -797,8 +804,7 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
                        le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
        unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
-                       metagroup < first_meta_bg)
+       if (!ext4_has_feature_meta_bg(sb) || metagroup < first_meta_bg)
                return ext4_bg_num_gdb_nometa(sb, group);
 
        return ext4_bg_num_gdb_meta(sb,group);
@@ -818,7 +824,7 @@ static unsigned ext4_num_base_meta_clusters(struct super_block *sb,
        /* Check for superblock and gdt backups in this group */
        num = ext4_bg_has_super(sb, block_group);
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
+       if (!ext4_has_feature_meta_bg(sb) ||
            block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
                          sbi->s_desc_per_block) {
                if (num) {
index 3522340c7a99ca80857f969b391ade54456b422e..02ddec6d8a7da3135cef70cc2960bd8789f20378 100644 (file)
@@ -234,7 +234,7 @@ int ext4_check_blockref(const char *function, unsigned int line,
                        es->s_last_error_block = cpu_to_le64(blk);
                        ext4_error_inode(inode, function, line, blk,
                                         "invalid block");
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
        }
        return 0;
index 45731558138c8e00cb3126f077bb0e9be7714d6f..af06830bfc00c743369737551e7bceea3b61eede 100644 (file)
@@ -253,8 +253,7 @@ typedef enum {
        EXT4_ENCRYPT,
 } ext4_direction_t;
 
-static int ext4_page_crypto(struct ext4_crypto_ctx *ctx,
-                           struct inode *inode,
+static int ext4_page_crypto(struct inode *inode,
                            ext4_direction_t rw,
                            pgoff_t index,
                            struct page *src_page,
@@ -296,7 +295,6 @@ static int ext4_page_crypto(struct ext4_crypto_ctx *ctx,
        else
                res = crypto_ablkcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
@@ -353,7 +351,7 @@ struct page *ext4_encrypt(struct inode *inode,
        if (IS_ERR(ciphertext_page))
                goto errout;
        ctx->w.control_page = plaintext_page;
-       err = ext4_page_crypto(ctx, inode, EXT4_ENCRYPT, plaintext_page->index,
+       err = ext4_page_crypto(inode, EXT4_ENCRYPT, plaintext_page->index,
                               plaintext_page, ciphertext_page);
        if (err) {
                ciphertext_page = ERR_PTR(err);
@@ -378,31 +376,14 @@ struct page *ext4_encrypt(struct inode *inode,
  *
  * Return: Zero on success, non-zero otherwise.
  */
-int ext4_decrypt(struct ext4_crypto_ctx *ctx, struct page *page)
+int ext4_decrypt(struct page *page)
 {
        BUG_ON(!PageLocked(page));
 
-       return ext4_page_crypto(ctx, page->mapping->host,
+       return ext4_page_crypto(page->mapping->host,
                                EXT4_DECRYPT, page->index, page, page);
 }
 
-/*
- * Convenience function which takes care of allocating and
- * deallocating the encryption context
- */
-int ext4_decrypt_one(struct inode *inode, struct page *page)
-{
-       int ret;
-
-       struct ext4_crypto_ctx *ctx = ext4_get_crypto_ctx(inode);
-
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-       ret = ext4_decrypt(ctx, page);
-       ext4_release_crypto_ctx(ctx);
-       return ret;
-}
-
 int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
 {
        struct ext4_crypto_ctx  *ctx;
@@ -411,7 +392,13 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
        ext4_lblk_t             lblk = ex->ee_block;
        ext4_fsblk_t            pblk = ext4_ext_pblock(ex);
        unsigned int            len = ext4_ext_get_actual_len(ex);
-       int                     err = 0;
+       int                     ret, err = 0;
+
+#if 0
+       ext4_msg(inode->i_sb, KERN_CRIT,
+                "ext4_encrypted_zeroout ino %lu lblk %u len %u",
+                (unsigned long) inode->i_ino, lblk, len);
+#endif
 
        BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
 
@@ -426,7 +413,7 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
        }
 
        while (len--) {
-               err = ext4_page_crypto(ctx, inode, EXT4_ENCRYPT, lblk,
+               err = ext4_page_crypto(inode, EXT4_ENCRYPT, lblk,
                                       ZERO_PAGE(0), ciphertext_page);
                if (err)
                        goto errout;
@@ -437,17 +424,26 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
                        goto errout;
                }
                bio->bi_bdev = inode->i_sb->s_bdev;
-               bio->bi_iter.bi_sector = pblk;
-               err = bio_add_page(bio, ciphertext_page,
+               bio->bi_iter.bi_sector =
+                       pblk << (inode->i_sb->s_blocksize_bits - 9);
+               ret = bio_add_page(bio, ciphertext_page,
                                   inode->i_sb->s_blocksize, 0);
-               if (err) {
+               if (ret != inode->i_sb->s_blocksize) {
+                       /* should never happen! */
+                       ext4_msg(inode->i_sb, KERN_ERR,
+                                "bio_add_page failed: %d", ret);
+                       WARN_ON(1);
                        bio_put(bio);
+                       err = -EIO;
                        goto errout;
                }
                err = submit_bio_wait(WRITE, bio);
+               if ((err == 0) && bio->bi_error)
+                       err = -EIO;
                bio_put(bio);
                if (err)
                        goto errout;
+               lblk++; pblk++;
        }
        err = 0;
 errout:
index 847f919c84d9cc382889935baac16b6b8a1064e2..2fbef8a14760f4095300c9fdc0edcdc2909f4a65 100644 (file)
@@ -120,7 +120,6 @@ static int ext4_fname_encrypt(struct inode *inode,
        ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
        res = crypto_ablkcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
@@ -182,7 +181,6 @@ static int ext4_fname_decrypt(struct inode *inode,
        ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
        res = crypto_ablkcipher_decrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
index 5c52c79dea4625c4a73d7d6195da9c1e39d6f02b..c5882b36e5582d0005582d0fe3ac86cab70d9c9c 100644 (file)
@@ -71,7 +71,6 @@ static int ext4_derive_key_aes(char deriving_key[EXT4_AES_128_ECB_KEY_SIZE],
                                     EXT4_AES_256_XTS_KEY_SIZE, NULL);
        res = crypto_ablkcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
-               BUG_ON(req->base.data != &ecr);
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
@@ -208,7 +207,12 @@ retry:
                goto out;
        }
        crypt_info->ci_keyring_key = keyring_key;
-       BUG_ON(keyring_key->type != &key_type_logon);
+       if (keyring_key->type != &key_type_logon) {
+               printk_once(KERN_WARNING
+                           "ext4: key type must be logon\n");
+               res = -ENOKEY;
+               goto out;
+       }
        ukp = user_key_payload(keyring_key);
        if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
                res = -EINVAL;
@@ -217,7 +221,13 @@ retry:
        master_key = (struct ext4_encryption_key *)ukp->data;
        BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
                     EXT4_KEY_DERIVATION_NONCE_SIZE);
-       BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
+       if (master_key->size != EXT4_AES_256_XTS_KEY_SIZE) {
+               printk_once(KERN_WARNING
+                           "ext4: key size incorrect: %d\n",
+                           master_key->size);
+               res = -ENOKEY;
+               goto out;
+       }
        res = ext4_derive_key_aes(ctx.nonce, master_key->raw,
                                  raw_key);
        if (res)
index a640ec2c4b134a16a3bb374872a57643f12f3e60..ad050698143fde483e9c5cddc5e32c88041a9b29 100644 (file)
@@ -150,7 +150,8 @@ int ext4_is_child_context_consistent_with_parent(struct inode *parent,
 
        if ((parent == NULL) || (child == NULL)) {
                pr_err("parent %p child %p\n", parent, child);
-               BUG_ON(1);
+               WARN_ON(1);     /* Should never happen */
+               return 0;
        }
        /* no restrictions if the parent directory is not encrypted */
        if (!ext4_encrypted_inode(parent))
index f9e14911918ced4ca6b81ca913a6b60a5e997a5c..1d1bca74f84437172d96c26e648e6ed45e129725 100644 (file)
@@ -40,8 +40,7 @@ static int is_dx_dir(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
 
-       if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
-                    EXT4_FEATURE_COMPAT_DIR_INDEX) &&
+       if (ext4_has_feature_dir_index(inode->i_sb) &&
            ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
             ((inode->i_size >> sb->s_blocksize_bits) == 1) ||
             ext4_has_inline_data(inode)))
@@ -621,14 +620,14 @@ int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
        while ((char *) de < top) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
                                         buf, buf_size, offset))
-                       return -EIO;
+                       return -EFSCORRUPTED;
                nlen = EXT4_DIR_REC_LEN(de->name_len);
                rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
                de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
                offset += rlen;
        }
        if ((char *) de > top)
-               return -EIO;
+               return -EFSCORRUPTED;
 
        return 0;
 }
index fd1f28be529690898c67b5d93ef3ed69bb1e0e78..750063f7a50c6cc2b9808318538762be67ce098d 100644 (file)
@@ -374,6 +374,7 @@ struct flex_groups {
 #define EXT4_EA_INODE_FL               0x00200000 /* Inode used for large EA */
 #define EXT4_EOFBLOCKS_FL              0x00400000 /* Blocks allocated beyond EOF */
 #define EXT4_INLINE_DATA_FL            0x10000000 /* Inode has inline data. */
+#define EXT4_PROJINHERIT_FL            0x20000000 /* Create with parents projid */
 #define EXT4_RESERVED_FL               0x80000000 /* reserved for ext4 lib */
 
 #define EXT4_FL_USER_VISIBLE           0x004BDFFF /* User visible flags */
@@ -431,6 +432,7 @@ enum {
        EXT4_INODE_EA_INODE     = 21,   /* Inode used for large EA */
        EXT4_INODE_EOFBLOCKS    = 22,   /* Blocks allocated beyond EOF */
        EXT4_INODE_INLINE_DATA  = 28,   /* Data in inode. */
+       EXT4_INODE_PROJINHERIT  = 29,   /* Create with parents projid */
        EXT4_INODE_RESERVED     = 31,   /* reserved for ext4 lib */
 };
 
@@ -475,6 +477,7 @@ static inline void ext4_check_flag_values(void)
        CHECK_FLAG_VALUE(EA_INODE);
        CHECK_FLAG_VALUE(EOFBLOCKS);
        CHECK_FLAG_VALUE(INLINE_DATA);
+       CHECK_FLAG_VALUE(PROJINHERIT);
        CHECK_FLAG_VALUE(RESERVED);
 }
 
@@ -692,6 +695,7 @@ struct ext4_inode {
        __le32  i_crtime;       /* File Creation time */
        __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
        __le32  i_version_hi;   /* high 32 bits for 64-bit version */
+       __le32  i_projid;       /* Project ID */
 };
 
 struct move_extent {
@@ -1019,6 +1023,9 @@ struct ext4_inode_info {
 #define EXT4_MOUNT2_HURD_COMPAT                0x00000004 /* Support HURD-castrated
                                                      file systems */
 
+#define EXT4_MOUNT2_EXPLICIT_JOURNAL_CHECKSUM  0x00000008 /* User explicitly
+                                               specified journal checksum */
+
 #define clear_opt(sb, opt)             EXT4_SB(sb)->s_mount_opt &= \
                                                ~EXT4_MOUNT_##opt
 #define set_opt(sb, opt)               EXT4_SB(sb)->s_mount_opt |= \
@@ -1179,7 +1186,9 @@ struct ext4_super_block {
        __u8    s_encrypt_algos[4];     /* Encryption algorithms in use  */
        __u8    s_encrypt_pw_salt[16];  /* Salt used for string2key algorithm */
        __le32  s_lpf_ino;              /* Location of the lost+found inode */
-       __le32  s_reserved[100];        /* Padding to the end of the block */
+       __le32  s_prj_quota_inum;       /* inode for tracking project quota */
+       __le32  s_checksum_seed;        /* crc32c(uuid) if csum_seed set */
+       __le32  s_reserved[98];         /* Padding to the end of the block */
        __le32  s_checksum;             /* crc32c(superblock) */
 };
 
@@ -1522,6 +1531,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
  * Feature set definitions
  */
 
+/* Use the ext4_{has,set,clear}_feature_* helpers; these will be removed */
 #define EXT4_HAS_COMPAT_FEATURE(sb,mask)                       \
        ((EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask)) != 0)
 #define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask)                    \
@@ -1566,6 +1576,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
  */
 #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 #define EXT4_FEATURE_RO_COMPAT_READONLY                0x1000
+#define EXT4_FEATURE_RO_COMPAT_PROJECT         0x2000
 
 #define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
@@ -1578,11 +1589,99 @@ static inline int ext4_encrypted_inode(struct inode *inode)
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG          0x0200
 #define EXT4_FEATURE_INCOMPAT_EA_INODE         0x0400 /* EA in inode */
 #define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000 /* data in dirent */
-#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED                0x2000
 #define EXT4_FEATURE_INCOMPAT_LARGEDIR         0x4000 /* >2GB or 3-lvl htree */
 #define EXT4_FEATURE_INCOMPAT_INLINE_DATA      0x8000 /* data in inode */
 #define EXT4_FEATURE_INCOMPAT_ENCRYPT          0x10000
 
+#define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_compat & \
+               cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_compat |= \
+               cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_compat &= \
+               ~cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \
+}
+
+#define EXT4_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \
+               cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_ro_compat |= \
+               cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_ro_compat &= \
+               ~cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \
+}
+
+#define EXT4_FEATURE_INCOMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_incompat & \
+               cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_incompat |= \
+               cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+       EXT4_SB(sb)->s_es->s_feature_incompat &= \
+               ~cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \
+}
+
+EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc,                DIR_PREALLOC)
+EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes,       IMAGIC_INODES)
+EXT4_FEATURE_COMPAT_FUNCS(journal,             HAS_JOURNAL)
+EXT4_FEATURE_COMPAT_FUNCS(xattr,               EXT_ATTR)
+EXT4_FEATURE_COMPAT_FUNCS(resize_inode,                RESIZE_INODE)
+EXT4_FEATURE_COMPAT_FUNCS(dir_index,           DIR_INDEX)
+EXT4_FEATURE_COMPAT_FUNCS(sparse_super2,       SPARSE_SUPER2)
+
+EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super,     SPARSE_SUPER)
+EXT4_FEATURE_RO_COMPAT_FUNCS(large_file,       LARGE_FILE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(btree_dir,                BTREE_DIR)
+EXT4_FEATURE_RO_COMPAT_FUNCS(huge_file,                HUGE_FILE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(gdt_csum,         GDT_CSUM)
+EXT4_FEATURE_RO_COMPAT_FUNCS(dir_nlink,                DIR_NLINK)
+EXT4_FEATURE_RO_COMPAT_FUNCS(extra_isize,      EXTRA_ISIZE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(quota,            QUOTA)
+EXT4_FEATURE_RO_COMPAT_FUNCS(bigalloc,         BIGALLOC)
+EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum,    METADATA_CSUM)
+EXT4_FEATURE_RO_COMPAT_FUNCS(readonly,         READONLY)
+EXT4_FEATURE_RO_COMPAT_FUNCS(project,          PROJECT)
+
+EXT4_FEATURE_INCOMPAT_FUNCS(compression,       COMPRESSION)
+EXT4_FEATURE_INCOMPAT_FUNCS(filetype,          FILETYPE)
+EXT4_FEATURE_INCOMPAT_FUNCS(journal_needs_recovery,    RECOVER)
+EXT4_FEATURE_INCOMPAT_FUNCS(journal_dev,       JOURNAL_DEV)
+EXT4_FEATURE_INCOMPAT_FUNCS(meta_bg,           META_BG)
+EXT4_FEATURE_INCOMPAT_FUNCS(extents,           EXTENTS)
+EXT4_FEATURE_INCOMPAT_FUNCS(64bit,             64BIT)
+EXT4_FEATURE_INCOMPAT_FUNCS(mmp,               MMP)
+EXT4_FEATURE_INCOMPAT_FUNCS(flex_bg,           FLEX_BG)
+EXT4_FEATURE_INCOMPAT_FUNCS(ea_inode,          EA_INODE)
+EXT4_FEATURE_INCOMPAT_FUNCS(dirdata,           DIRDATA)
+EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed,         CSUM_SEED)
+EXT4_FEATURE_INCOMPAT_FUNCS(largedir,          LARGEDIR)
+EXT4_FEATURE_INCOMPAT_FUNCS(inline_data,       INLINE_DATA)
+EXT4_FEATURE_INCOMPAT_FUNCS(encrypt,           ENCRYPT)
+
 #define EXT2_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
                                         EXT4_FEATURE_INCOMPAT_META_BG)
@@ -1598,7 +1697,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
                                         EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
 
-#define EXT4_FEATURE_COMPAT_SUPP       EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT4_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
 #define EXT4_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
                                         EXT4_FEATURE_INCOMPAT_RECOVER| \
                                         EXT4_FEATURE_INCOMPAT_META_BG| \
@@ -1607,7 +1706,8 @@ static inline int ext4_encrypted_inode(struct inode *inode)
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG| \
                                         EXT4_FEATURE_INCOMPAT_MMP | \
                                         EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
-                                        EXT4_FEATURE_INCOMPAT_ENCRYPT)
+                                        EXT4_FEATURE_INCOMPAT_ENCRYPT | \
+                                        EXT4_FEATURE_INCOMPAT_CSUM_SEED)
 #define EXT4_FEATURE_RO_COMPAT_SUPP    (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
@@ -1619,6 +1719,40 @@ static inline int ext4_encrypted_inode(struct inode *inode)
                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
                                         EXT4_FEATURE_RO_COMPAT_QUOTA)
 
+#define EXTN_FEATURE_FUNCS(ver) \
+static inline bool ext4_has_unknown_ext##ver##_compat_features(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_compat & \
+               cpu_to_le32(~EXT##ver##_FEATURE_COMPAT_SUPP)) != 0); \
+} \
+static inline bool ext4_has_unknown_ext##ver##_ro_compat_features(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \
+               cpu_to_le32(~EXT##ver##_FEATURE_RO_COMPAT_SUPP)) != 0); \
+} \
+static inline bool ext4_has_unknown_ext##ver##_incompat_features(struct super_block *sb) \
+{ \
+       return ((EXT4_SB(sb)->s_es->s_feature_incompat & \
+               cpu_to_le32(~EXT##ver##_FEATURE_INCOMPAT_SUPP)) != 0); \
+}
+
+EXTN_FEATURE_FUNCS(2)
+EXTN_FEATURE_FUNCS(3)
+EXTN_FEATURE_FUNCS(4)
+
+static inline bool ext4_has_compat_features(struct super_block *sb)
+{
+       return (EXT4_SB(sb)->s_es->s_feature_compat != 0);
+}
+static inline bool ext4_has_ro_compat_features(struct super_block *sb)
+{
+       return (EXT4_SB(sb)->s_es->s_feature_ro_compat != 0);
+}
+static inline bool ext4_has_incompat_features(struct super_block *sb)
+{
+       return (EXT4_SB(sb)->s_es->s_feature_incompat != 0);
+}
+
 /*
  * Default values for user and/or group using reserved blocks
  */
@@ -1769,8 +1903,7 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
  * (c) Daniel Phillips, 2001
  */
 
-#define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb, \
-                                     EXT4_FEATURE_COMPAT_DIR_INDEX) && \
+#define is_dx(dir) (ext4_has_feature_dir_index((dir)->i_sb) && \
                    ext4_test_inode_flag((dir), EXT4_INODE_INDEX))
 #define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
 #define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
@@ -2063,8 +2196,7 @@ void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx);
 void ext4_restore_control_page(struct page *data_page);
 struct page *ext4_encrypt(struct inode *inode,
                          struct page *plaintext_page);
-int ext4_decrypt(struct ext4_crypto_ctx *ctx, struct page *page);
-int ext4_decrypt_one(struct inode *inode, struct page *page);
+int ext4_decrypt(struct page *page);
 int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex);
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
@@ -2072,7 +2204,7 @@ int ext4_init_crypto(void);
 void ext4_exit_crypto(void);
 static inline int ext4_sb_has_crypto(struct super_block *sb)
 {
-       return EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
+       return ext4_has_feature_encrypt(sb);
 }
 #else
 static inline int ext4_init_crypto(void) { return 0; }
@@ -2193,8 +2325,7 @@ int ext4_insert_dentry(struct inode *dir,
                       struct ext4_filename *fname);
 static inline void ext4_update_dx_flag(struct inode *inode)
 {
-       if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
-                                    EXT4_FEATURE_COMPAT_DIR_INDEX))
+       if (!ext4_has_feature_dir_index(inode->i_sb))
                ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
 }
 static unsigned char ext4_filetype_table[] = {
@@ -2203,8 +2334,7 @@ static unsigned char ext4_filetype_table[] = {
 
 static inline  unsigned char get_dtype(struct super_block *sb, int filetype)
 {
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
-           (filetype >= EXT4_FT_MAX))
+       if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX)
                return DT_UNKNOWN;
 
        return ext4_filetype_table[filetype];
@@ -2245,6 +2375,7 @@ extern int ext4_init_inode_table(struct super_block *sb,
 extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
 
 /* mballoc.c */
+extern const struct file_operations ext4_seq_mb_groups_fops;
 extern long ext4_mb_stats;
 extern long ext4_mb_max_to_scan;
 extern int ext4_mb_init(struct super_block *);
@@ -2372,6 +2503,7 @@ extern int ext4_group_extend(struct super_block *sb,
 extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
 
 /* super.c */
+extern int ext4_seq_options_show(struct seq_file *seq, void *offset);
 extern int ext4_calculate_overhead(struct super_block *sb);
 extern void ext4_superblock_csum_set(struct super_block *sb);
 extern void *ext4_kvmalloc(size_t size, gfp_t flags);
@@ -2534,15 +2666,13 @@ extern int ext4_register_li_request(struct super_block *sb,
 
 static inline int ext4_has_group_desc_csum(struct super_block *sb)
 {
-       return EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ||
-              (EXT4_SB(sb)->s_chksum_driver != NULL);
+       return ext4_has_feature_gdt_csum(sb) ||
+              EXT4_SB(sb)->s_chksum_driver != NULL;
 }
 
 static inline int ext4_has_metadata_csum(struct super_block *sb)
 {
-       WARN_ON_ONCE(EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+       WARN_ON_ONCE(ext4_has_feature_metadata_csum(sb) &&
                     !EXT4_SB(sb)->s_chksum_driver);
 
        return (EXT4_SB(sb)->s_chksum_driver != NULL);
@@ -2889,7 +3019,7 @@ static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
 static inline void ext4_set_de_type(struct super_block *sb,
                                struct ext4_dir_entry_2 *de,
                                umode_t mode) {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE))
+       if (ext4_has_feature_filetype(sb))
                de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
 }
 
@@ -2903,6 +3033,12 @@ extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
 extern const struct inode_operations ext4_symlink_inode_operations;
 extern const struct inode_operations ext4_fast_symlink_inode_operations;
 
+/* sysfs.c */
+extern int ext4_register_sysfs(struct super_block *sb);
+extern void ext4_unregister_sysfs(struct super_block *sb);
+extern int __init ext4_init_sysfs(void);
+extern void ext4_exit_sysfs(void);
+
 /* block_validity */
 extern void ext4_release_system_zone(struct super_block *sb);
 extern int ext4_setup_system_zone(struct super_block *sb);
@@ -3049,4 +3185,7 @@ extern void ext4_resize_end(struct super_block *sb);
 
 #endif /* __KERNEL__ */
 
+#define EFSBADCRC      EBADMSG         /* Bad CRC detected */
+#define EFSCORRUPTED   EUCLEAN         /* Filesystem is corrupted */
+
 #endif /* _EXT4_H */
index d4184318181878b023931078377ae17c9568a208..e770c1ee4613ed6084518f2ec9dca0ff9e53a29a 100644 (file)
@@ -88,13 +88,13 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
                return 0;
        }
 
+       err = handle->h_err;
        if (!handle->h_transaction) {
-               err = jbd2_journal_stop(handle);
-               return handle->h_err ? handle->h_err : err;
+               rc = jbd2_journal_stop(handle);
+               return err ? err : rc;
        }
 
        sb = handle->h_transaction->t_journal->j_private;
-       err = handle->h_err;
        rc = jbd2_journal_stop(handle);
 
        if (!err)
index 9c5b49fb281e16f1717b989d31dd55ade6c03f8d..5f58462110953dc61c9bd85101acd69c33a51331 100644 (file)
@@ -34,8 +34,7 @@
  */
 
 #define EXT4_SINGLEDATA_TRANS_BLOCKS(sb)                               \
-       (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)   \
-        ? 20U : 8U)
+       (ext4_has_feature_extents(sb) ? 20U : 8U)
 
 /* Extended attribute operations touch at most two data buffers,
  * two bitmap buffers, and two group summaries, in addition to the inode
 /* Amount of blocks needed for quota update - we know that the structure was
  * allocated so we need to update only data block */
 #define EXT4_QUOTA_TRANS_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
-               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
-               1 : 0)
+               ext4_has_feature_quota(sb)) ? 1 : 0)
 /* Amount of blocks needed for quota insert/delete - we do some block writes
  * but inode, sb and group updates are done only once */
 #define EXT4_QUOTA_INIT_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
-               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
+               ext4_has_feature_quota(sb)) ?\
                (DQUOT_INIT_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
                 +3+DQUOT_INIT_REWRITE) : 0)
 
 #define EXT4_QUOTA_DEL_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
-               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
+               ext4_has_feature_quota(sb)) ?\
                (DQUOT_DEL_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
                 +3+DQUOT_DEL_REWRITE) : 0)
 #else
index 2553aa8b608d84d1673190ea634c5e84c86d9f0b..551353b1b17ab930ead8eff62ee3a699b4cfe10f 100644 (file)
@@ -442,7 +442,7 @@ static int __ext4_ext_check(const char *function, unsigned int line,
                            int depth, ext4_fsblk_t pblk)
 {
        const char *error_msg;
-       int max = 0;
+       int max = 0, err = -EFSCORRUPTED;
 
        if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
                error_msg = "invalid magic";
@@ -473,6 +473,7 @@ static int __ext4_ext_check(const char *function, unsigned int line,
        if (ext_depth(inode) != depth &&
            !ext4_extent_block_csum_verify(inode, eh)) {
                error_msg = "extent tree corrupted";
+               err = -EFSBADCRC;
                goto corrupted;
        }
        return 0;
@@ -485,7 +486,7 @@ corrupted:
                         le16_to_cpu(eh->eh_magic),
                         le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
                         max, le16_to_cpu(eh->eh_depth), depth);
-       return -EIO;
+       return err;
 }
 
 #define ext4_ext_check(inode, eh, depth, pblk)                 \
@@ -899,7 +900,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
 
                bh = read_extent_tree_block(inode, path[ppos].p_block, --i,
                                            flags);
-               if (unlikely(IS_ERR(bh))) {
+               if (IS_ERR(bh)) {
                        ret = PTR_ERR(bh);
                        goto err;
                }
@@ -910,7 +911,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
                        put_bh(bh);
                        EXT4_ERROR_INODE(inode,
                                         "ppos %d > depth %d", ppos, depth);
-                       ret = -EIO;
+                       ret = -EFSCORRUPTED;
                        goto err;
                }
                path[ppos].p_bh = bh;
@@ -959,7 +960,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                EXT4_ERROR_INODE(inode,
                                 "logical %d == ei_block %d!",
                                 logical, le32_to_cpu(curp->p_idx->ei_block));
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
@@ -968,7 +969,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                                 "eh_entries %d >= eh_max %d!",
                                 le16_to_cpu(curp->p_hdr->eh_entries),
                                 le16_to_cpu(curp->p_hdr->eh_max));
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
@@ -992,7 +993,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
 
        if (unlikely(ix > EXT_MAX_INDEX(curp->p_hdr))) {
                EXT4_ERROR_INODE(inode, "ix > EXT_MAX_INDEX!");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        ix->ei_block = cpu_to_le32(logical);
@@ -1001,7 +1002,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
 
        if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) {
                EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        err = ext4_ext_dirty(handle, inode, curp);
@@ -1042,7 +1043,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
         * border from split point */
        if (unlikely(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr))) {
                EXT4_ERROR_INODE(inode, "p_ext > EXT_MAX_EXTENT!");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {
                border = path[depth].p_ext[1].ee_block;
@@ -1086,7 +1087,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        newblock = ablocks[--a];
        if (unlikely(newblock == 0)) {
                EXT4_ERROR_INODE(inode, "newblock == 0!");
-               err = -EIO;
+               err = -EFSCORRUPTED;
                goto cleanup;
        }
        bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS);
@@ -1112,7 +1113,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                EXT4_ERROR_INODE(inode, "eh_entries %d != eh_max %d!",
                                 path[depth].p_hdr->eh_entries,
                                 path[depth].p_hdr->eh_max);
-               err = -EIO;
+               err = -EFSCORRUPTED;
                goto cleanup;
        }
        /* start copy from next extent */
@@ -1151,7 +1152,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        k = depth - at - 1;
        if (unlikely(k < 0)) {
                EXT4_ERROR_INODE(inode, "k %d < 0!", k);
-               err = -EIO;
+               err = -EFSCORRUPTED;
                goto cleanup;
        }
        if (k)
@@ -1191,7 +1192,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                        EXT4_ERROR_INODE(inode,
                                         "EXT_MAX_INDEX != EXT_LAST_INDEX ee_block %d!",
                                         le32_to_cpu(path[i].p_ext->ee_block));
-                       err = -EIO;
+                       err = -EFSCORRUPTED;
                        goto cleanup;
                }
                /* start copy indexes */
@@ -1425,7 +1426,7 @@ static int ext4_ext_search_left(struct inode *inode,
 
        if (unlikely(path == NULL)) {
                EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        depth = path->p_depth;
        *phys = 0;
@@ -1444,7 +1445,7 @@ static int ext4_ext_search_left(struct inode *inode,
                        EXT4_ERROR_INODE(inode,
                                         "EXT_FIRST_EXTENT != ex *logical %d ee_block %d!",
                                         *logical, le32_to_cpu(ex->ee_block));
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
                while (--depth >= 0) {
                        ix = path[depth].p_idx;
@@ -1455,7 +1456,7 @@ static int ext4_ext_search_left(struct inode *inode,
                                  EXT_FIRST_INDEX(path[depth].p_hdr) != NULL ?
                le32_to_cpu(EXT_FIRST_INDEX(path[depth].p_hdr)->ei_block) : 0,
                                  depth);
-                               return -EIO;
+                               return -EFSCORRUPTED;
                        }
                }
                return 0;
@@ -1465,7 +1466,7 @@ static int ext4_ext_search_left(struct inode *inode,
                EXT4_ERROR_INODE(inode,
                                 "logical %d < ee_block %d + ee_len %d!",
                                 *logical, le32_to_cpu(ex->ee_block), ee_len);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        *logical = le32_to_cpu(ex->ee_block) + ee_len - 1;
@@ -1495,7 +1496,7 @@ static int ext4_ext_search_right(struct inode *inode,
 
        if (unlikely(path == NULL)) {
                EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        depth = path->p_depth;
        *phys = 0;
@@ -1514,7 +1515,7 @@ static int ext4_ext_search_right(struct inode *inode,
                        EXT4_ERROR_INODE(inode,
                                         "first_extent(path[%d].p_hdr) != ex",
                                         depth);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
                while (--depth >= 0) {
                        ix = path[depth].p_idx;
@@ -1522,7 +1523,7 @@ static int ext4_ext_search_right(struct inode *inode,
                                EXT4_ERROR_INODE(inode,
                                                 "ix != EXT_FIRST_INDEX *logical %d!",
                                                 *logical);
-                               return -EIO;
+                               return -EFSCORRUPTED;
                        }
                }
                goto found_extent;
@@ -1532,7 +1533,7 @@ static int ext4_ext_search_right(struct inode *inode,
                EXT4_ERROR_INODE(inode,
                                 "logical %d < ee_block %d + ee_len %d!",
                                 *logical, le32_to_cpu(ex->ee_block), ee_len);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) {
@@ -1670,7 +1671,7 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
        if (unlikely(ex == NULL || eh == NULL)) {
                EXT4_ERROR_INODE(inode,
                                 "ex %p == NULL or eh %p == NULL", ex, eh);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        if (depth == 0) {
@@ -1938,14 +1939,14 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                mb_flags |= EXT4_MB_DELALLOC_RESERVED;
        if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
                EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        depth = ext_depth(inode);
        ex = path[depth].p_ext;
        eh = path[depth].p_hdr;
        if (unlikely(path[depth].p_hdr == NULL)) {
                EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /* try to insert block into found extent and return */
@@ -2172,7 +2173,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
                if (unlikely(path[depth].p_hdr == NULL)) {
                        up_read(&EXT4_I(inode)->i_data_sem);
                        EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
-                       err = -EIO;
+                       err = -EFSCORRUPTED;
                        break;
                }
                ex = path[depth].p_ext;
@@ -2241,7 +2242,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
 
                if (unlikely(es.es_len == 0)) {
                        EXT4_ERROR_INODE(inode, "es.es_len == 0");
-                       err = -EIO;
+                       err = -EFSCORRUPTED;
                        break;
                }
 
@@ -2264,7 +2265,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
                                                 "next extent == %u, next "
                                                 "delalloc extent = %u",
                                                 next, next_del);
-                               err = -EIO;
+                               err = -EFSCORRUPTED;
                                break;
                        }
                }
@@ -2363,7 +2364,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
        leaf = ext4_idx_pblock(path->p_idx);
        if (unlikely(path->p_hdr->eh_entries == 0)) {
                EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        err = ext4_ext_get_access(handle, inode, path);
        if (err)
@@ -2612,7 +2613,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        eh = path[depth].p_hdr;
        if (unlikely(path[depth].p_hdr == NULL)) {
                EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        /* find where to start removing */
        ex = path[depth].p_ext;
@@ -2666,7 +2667,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                                         "on extent %u:%u",
                                         start, end, ex_ee_block,
                                         ex_ee_block + ex_ee_len - 1);
-                       err = -EIO;
+                       err = -EFSCORRUPTED;
                        goto out;
                } else if (a != ex_ee_block) {
                        /* remove tail of the extent */
@@ -2841,7 +2842,7 @@ again:
                                EXT4_ERROR_INODE(inode,
                                                 "path[%d].p_hdr == NULL",
                                                 depth);
-                               err = -EIO;
+                               err = -EFSCORRUPTED;
                        }
                        goto out;
                }
@@ -2920,7 +2921,7 @@ again:
                i = 0;
 
                if (ext4_ext_check(inode, path[0].p_hdr, depth, 0)) {
-                       err = -EIO;
+                       err = -EFSCORRUPTED;
                        goto out;
                }
        }
@@ -2978,7 +2979,7 @@ again:
                         * Should be a no-op if we did IO above. */
                        cond_resched();
                        if (WARN_ON(i + 1 > depth)) {
-                               err = -EIO;
+                               err = -EFSCORRUPTED;
                                break;
                        }
                        path[i + 1].p_bh = bh;
@@ -3054,7 +3055,7 @@ void ext4_ext_init(struct super_block *sb)
         * possible initialization would be here
         */
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_extents(sb)) {
 #if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS)
                printk(KERN_INFO "EXT4-fs: file extents enabled"
 #ifdef AGGRESSIVE_TEST
@@ -3081,7 +3082,7 @@ void ext4_ext_init(struct super_block *sb)
  */
 void ext4_ext_release(struct super_block *sb)
 {
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS))
+       if (!ext4_has_feature_extents(sb))
                return;
 
 #ifdef EXTENTS_STATS
@@ -3345,7 +3346,7 @@ static int ext4_split_extent(handle_t *handle,
        if (!ex) {
                EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
                                 (unsigned long) map->m_lblk);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        unwritten = ext4_ext_is_unwritten(ex);
        split_flag1 = 0;
@@ -3558,6 +3559,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                max_zeroout = sbi->s_extent_max_zeroout_kb >>
                        (inode->i_sb->s_blocksize_bits - 10);
 
+       if (ext4_encrypted_inode(inode))
+               max_zeroout = 0;
+
        /* If extent is less than s_max_zeroout_kb, zeroout directly */
        if (max_zeroout && (ee_len <= max_zeroout)) {
                err = ext4_ext_zeroout(inode, ex);
@@ -3970,7 +3974,7 @@ convert_initialized_extent(handle_t *handle, struct inode *inode,
                if (!ex) {
                        EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
                                         (unsigned long) map->m_lblk);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
        }
 
@@ -4308,7 +4312,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                                 "lblock: %lu, depth: %d pblock %lld",
                                 (unsigned long) map->m_lblk, depth,
                                 path[depth].p_block);
-               err = -EIO;
+               err = -EFSCORRUPTED;
                goto out2;
        }
 
@@ -5271,7 +5275,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
                if (depth == path->p_depth) {
                        ex_start = path[depth].p_ext;
                        if (!ex_start)
-                               return -EIO;
+                               return -EFSCORRUPTED;
 
                        ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
 
@@ -5411,7 +5415,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
                if (!extent) {
                        EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
                                         (unsigned long) *iterator);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
                if (SHIFT == SHIFT_LEFT && *iterator >
                    le32_to_cpu(extent->ee_block)) {
@@ -5792,7 +5796,7 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
                int split = 0;
 
                path1 = ext4_find_extent(inode1, lblk1, NULL, EXT4_EX_NOCACHE);
-               if (unlikely(IS_ERR(path1))) {
+               if (IS_ERR(path1)) {
                        *erp = PTR_ERR(path1);
                        path1 = NULL;
                finish:
@@ -5800,7 +5804,7 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
                        goto repeat;
                }
                path2 = ext4_find_extent(inode2, lblk2, NULL, EXT4_EX_NOCACHE);
-               if (unlikely(IS_ERR(path2))) {
+               if (IS_ERR(path2)) {
                        *erp = PTR_ERR(path2);
                        path2 = NULL;
                        goto finish;
index 26724aeece7396a7b55e20c22e586b1776a5b190..ac748b3af1c1ca2f242ce99b3a260850ae150fc9 100644 (file)
@@ -1089,20 +1089,9 @@ static unsigned long ext4_es_scan(struct shrinker *shrink,
        return nr_shrunk;
 }
 
-static void *ext4_es_seq_shrinker_info_start(struct seq_file *seq, loff_t *pos)
+int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v)
 {
-       return *pos ? NULL : SEQ_START_TOKEN;
-}
-
-static void *
-ext4_es_seq_shrinker_info_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return NULL;
-}
-
-static int ext4_es_seq_shrinker_info_show(struct seq_file *seq, void *v)
-{
-       struct ext4_sb_info *sbi = seq->private;
+       struct ext4_sb_info *sbi = EXT4_SB((struct super_block *) seq->private);
        struct ext4_es_stats *es_stats = &sbi->s_es_stats;
        struct ext4_inode_info *ei, *max = NULL;
        unsigned int inode_cnt = 0;
@@ -1143,45 +1132,6 @@ static int ext4_es_seq_shrinker_info_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static void ext4_es_seq_shrinker_info_stop(struct seq_file *seq, void *v)
-{
-}
-
-static const struct seq_operations ext4_es_seq_shrinker_info_ops = {
-       .start = ext4_es_seq_shrinker_info_start,
-       .next  = ext4_es_seq_shrinker_info_next,
-       .stop  = ext4_es_seq_shrinker_info_stop,
-       .show  = ext4_es_seq_shrinker_info_show,
-};
-
-static int
-ext4_es_seq_shrinker_info_open(struct inode *inode, struct file *file)
-{
-       int ret;
-
-       ret = seq_open(file, &ext4_es_seq_shrinker_info_ops);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               m->private = PDE_DATA(inode);
-       }
-
-       return ret;
-}
-
-static int
-ext4_es_seq_shrinker_info_release(struct inode *inode, struct file *file)
-{
-       return seq_release(inode, file);
-}
-
-static const struct file_operations ext4_es_seq_shrinker_info_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ext4_es_seq_shrinker_info_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = ext4_es_seq_shrinker_info_release,
-};
-
 int ext4_es_register_shrinker(struct ext4_sb_info *sbi)
 {
        int err;
@@ -1210,10 +1160,6 @@ int ext4_es_register_shrinker(struct ext4_sb_info *sbi)
        if (err)
                goto err2;
 
-       if (sbi->s_proc)
-               proc_create_data("es_shrinker_info", S_IRUGO, sbi->s_proc,
-                                &ext4_es_seq_shrinker_info_fops, sbi);
-
        return 0;
 
 err2:
@@ -1225,8 +1171,6 @@ err1:
 
 void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi)
 {
-       if (sbi->s_proc)
-               remove_proc_entry("es_shrinker_info", sbi->s_proc);
        percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt);
        percpu_counter_destroy(&sbi->s_es_stats.es_stats_shk_cnt);
        unregister_shrinker(&sbi->s_es_shrinker);
index 691b52613ce457d1aefb85e01752999c9102e846..f7aa24f4642d83fd781fc2b69a5c4644098e3002 100644 (file)
@@ -172,4 +172,6 @@ static inline void ext4_es_store_pblock_status(struct extent_status *es,
 extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi);
 extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi);
 
+extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v);
+
 #endif /* _EXT4_EXTENTS_STATUS_H */
index 619bfc1fda8cc0956ba87bfd9e9fa20b41c10cee..1b8024d26f654c5458c7e84db5a2c439adc6500e 100644 (file)
@@ -64,7 +64,7 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
 }
 
 /* Initializes an uninitialized inode bitmap */
-static unsigned ext4_init_inode_bitmap(struct super_block *sb,
+static int ext4_init_inode_bitmap(struct super_block *sb,
                                       struct buffer_head *bh,
                                       ext4_group_t block_group,
                                       struct ext4_group_desc *gdp)
@@ -89,7 +89,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
                                           count);
                }
                set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return 0;
+               return -EFSBADCRC;
        }
 
        memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
@@ -99,7 +99,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
                                   EXT4_INODES_PER_GROUP(sb) / 8);
        ext4_group_desc_csum_set(sb, block_group, gdp);
 
-       return EXT4_INODES_PER_GROUP(sb);
+       return 0;
 }
 
 void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
@@ -112,6 +112,42 @@ void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
        put_bh(bh);
 }
 
+static int ext4_validate_inode_bitmap(struct super_block *sb,
+                                     struct ext4_group_desc *desc,
+                                     ext4_group_t block_group,
+                                     struct buffer_head *bh)
+{
+       ext4_fsblk_t    blk;
+       struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (buffer_verified(bh))
+               return 0;
+       if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
+               return -EFSCORRUPTED;
+
+       ext4_lock_group(sb, block_group);
+       blk = ext4_inode_bitmap(sb, desc);
+       if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
+                                          EXT4_INODES_PER_GROUP(sb) / 8)) {
+               ext4_unlock_group(sb, block_group);
+               ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
+                          "inode_bitmap = %llu", block_group, blk);
+               grp = ext4_get_group_info(sb, block_group);
+               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+                       int count;
+                       count = ext4_free_inodes_count(sb, desc);
+                       percpu_counter_sub(&sbi->s_freeinodes_counter,
+                                          count);
+               }
+               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
+               return -EFSBADCRC;
+       }
+       set_buffer_verified(bh);
+       ext4_unlock_group(sb, block_group);
+       return 0;
+}
+
 /*
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
@@ -124,12 +160,11 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
        struct ext4_group_desc *desc;
        struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
-       struct ext4_group_info *grp;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       int err;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               return NULL;
+               return ERR_PTR(-EFSCORRUPTED);
 
        bitmap_blk = ext4_inode_bitmap(sb, desc);
        bh = sb_getblk(sb, bitmap_blk);
@@ -137,7 +172,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                ext4_error(sb, "Cannot read inode bitmap - "
                            "block_group = %u, inode_bitmap = %llu",
                            block_group, bitmap_blk);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
        if (bitmap_uptodate(bh))
                goto verify;
@@ -150,12 +185,14 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
 
        ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-               ext4_init_inode_bitmap(sb, bh, block_group, desc);
+               err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
                set_buffer_verified(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
+               if (err)
+                       goto out;
                return bh;
        }
        ext4_unlock_group(sb, block_group);
@@ -182,31 +219,17 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                ext4_error(sb, "Cannot read inode bitmap - "
                           "block_group = %u, inode_bitmap = %llu",
                           block_group, bitmap_blk);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
 
 verify:
-       ext4_lock_group(sb, block_group);
-       if (!buffer_verified(bh) &&
-           !ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
-                                          EXT4_INODES_PER_GROUP(sb) / 8)) {
-               ext4_unlock_group(sb, block_group);
-               put_bh(bh);
-               ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
-                          "inode_bitmap = %llu", block_group, bitmap_blk);
-               grp = ext4_get_group_info(sb, block_group);
-               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
-                       int count;
-                       count = ext4_free_inodes_count(sb, desc);
-                       percpu_counter_sub(&sbi->s_freeinodes_counter,
-                                          count);
-               }
-               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return NULL;
-       }
-       ext4_unlock_group(sb, block_group);
-       set_buffer_verified(bh);
+       err = ext4_validate_inode_bitmap(sb, desc, block_group, bh);
+       if (err)
+               goto out;
        return bh;
+out:
+       put_bh(bh);
+       return ERR_PTR(err);
 }
 
 /*
@@ -286,8 +309,15 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
        /* Don't bother if the inode bitmap is corrupt. */
        grp = ext4_get_group_info(sb, block_group);
-       if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh)
+       if (IS_ERR(bitmap_bh)) {
+               fatal = PTR_ERR(bitmap_bh);
+               bitmap_bh = NULL;
+               goto error_return;
+       }
+       if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp))) {
+               fatal = -EFSCORRUPTED;
                goto error_return;
+       }
 
        BUFFER_TRACE(bitmap_bh, "get_write_access");
        fatal = ext4_journal_get_write_access(handle, bitmap_bh);
@@ -826,7 +856,9 @@ got_group:
                brelse(inode_bitmap_bh);
                inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
                /* Skip groups with suspicious inode tables */
-               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
+               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) ||
+                   IS_ERR(inode_bitmap_bh)) {
+                       inode_bitmap_bh = NULL;
                        if (++group == ngroups)
                                group = 0;
                        continue;
@@ -902,8 +934,8 @@ got:
                struct buffer_head *block_bitmap_bh;
 
                block_bitmap_bh = ext4_read_block_bitmap(sb, group);
-               if (!block_bitmap_bh) {
-                       err = -EIO;
+               if (IS_ERR(block_bitmap_bh)) {
+                       err = PTR_ERR(block_bitmap_bh);
                        goto out;
                }
                BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
@@ -1045,7 +1077,7 @@ got:
 
        ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
        ei->i_inline_off = 0;
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+       if (ext4_has_feature_inline_data(sb))
                ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
        ret = inode;
        err = dquot_alloc_inode(inode);
@@ -1060,7 +1092,7 @@ got:
        if (err)
                goto fail_free_drop;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_extents(sb)) {
                /* set extent flag only for directory, file and normal symlink*/
                if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) {
                        ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
@@ -1116,14 +1148,17 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
        /* Error cases - e2fsck has already cleaned up for us */
        if (ino > max_ino) {
                ext4_warning(sb, "bad orphan ino %lu!  e2fsck was run?", ino);
+               err = -EFSCORRUPTED;
                goto error;
        }
 
        block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
        bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
        bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
-       if (!bitmap_bh) {
-               ext4_warning(sb, "inode bitmap error for orphan %lu", ino);
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               ext4_warning(sb, "inode bitmap error %ld for orphan %lu",
+                            ino, err);
                goto error;
        }
 
@@ -1198,8 +1233,10 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
                desc_count += ext4_free_inodes_count(sb, gdp);
                brelse(bitmap_bh);
                bitmap_bh = ext4_read_inode_bitmap(sb, i);
-               if (!bitmap_bh)
+               if (IS_ERR(bitmap_bh)) {
+                       bitmap_bh = NULL;
                        continue;
+               }
 
                x = ext4_count_free(bitmap_bh->b_data,
                                    EXT4_INODES_PER_GROUP(sb) / 8);
index 2468261748b2c53a7ee5ebafadc388a8bb2835ad..355ef9c36c878e3932f356176abcaefb88b9d4cb 100644 (file)
@@ -562,11 +562,10 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
        /*
         * Okay, we need to do block allocation.
        */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
-                                      EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+       if (ext4_has_feature_bigalloc(inode->i_sb)) {
                EXT4_ERROR_INODE(inode, "Can't allocate blocks for "
                                 "non-extent mapped inodes with bigalloc");
-               return -EUCLEAN;
+               return -EFSCORRUPTED;
        }
 
        /* Set up for the direct block allocation */
index cd944a7a99cdcf0d5f53c7823003f3f6d7df6667..d884989cc83dd99238a710f8131ab38b1139c7ca 100644 (file)
@@ -434,8 +434,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
        memset((void *)ext4_raw_inode(&is.iloc)->i_block,
                0, EXT4_MIN_INLINE_DATA_SIZE);
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
-                                     EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_extents(inode->i_sb)) {
                if (S_ISDIR(inode->i_mode) ||
                    S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
                        ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
index 60aaecd5598b32798cb114cbd473d5818af7c692..7d1aad1d9313155f3780cde3923710fe7f60ea1c 100644 (file)
@@ -378,7 +378,7 @@ static int __check_block_validity(struct inode *inode, const char *func,
                                 "lblock %lu mapped to illegal pblock "
                                 "(length %d)", (unsigned long) map->m_lblk,
                                 map->m_len);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -480,7 +480,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
 
        /* We can handle the block number less than EXT_MAX_BLOCKS */
        if (unlikely(map->m_lblk >= EXT_MAX_BLOCKS))
-               return -EIO;
+               return -EFSCORRUPTED;
 
        /* Lookup extent status tree firstly */
        if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
@@ -965,7 +965,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
        if (unlikely(err))
                page_zero_new_buffers(page, from, to);
        else if (decrypt)
-               err = ext4_decrypt_one(inode, page);
+               err = ext4_decrypt(page);
        return err;
 }
 #endif
@@ -1181,6 +1181,38 @@ errout:
        return ret ? ret : copied;
 }
 
+/*
+ * This is a private version of page_zero_new_buffers() which doesn't
+ * set the buffer to be dirty, since in data=journalled mode we need
+ * to call ext4_handle_dirty_metadata() instead.
+ */
+static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+{
+       unsigned int block_start = 0, block_end;
+       struct buffer_head *head, *bh;
+
+       bh = head = page_buffers(page);
+       do {
+               block_end = block_start + bh->b_size;
+               if (buffer_new(bh)) {
+                       if (block_end > from && block_start < to) {
+                               if (!PageUptodate(page)) {
+                                       unsigned start, size;
+
+                                       start = max(from, block_start);
+                                       size = min(to, block_end) - start;
+
+                                       zero_user(page, start, size);
+                                       set_buffer_uptodate(bh);
+                               }
+                               clear_buffer_new(bh);
+                       }
+               }
+               block_start = block_end;
+               bh = bh->b_this_page;
+       } while (bh != head);
+}
+
 static int ext4_journalled_write_end(struct file *file,
                                     struct address_space *mapping,
                                     loff_t pos, unsigned len, unsigned copied,
@@ -1207,7 +1239,7 @@ static int ext4_journalled_write_end(struct file *file,
                if (copied < len) {
                        if (!PageUptodate(page))
                                copied = 0;
-                       page_zero_new_buffers(page, from+copied, to);
+                       zero_new_buffers(page, from+copied, to);
                }
 
                ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
@@ -1815,11 +1847,22 @@ static int ext4_writepage(struct page *page,
         * the page. But we may reach here when we do a journal commit via
         * journal_submit_inode_data_buffers() and in that case we must write
         * allocated buffers to achieve data=ordered mode guarantees.
+        *
+        * Also, if there is only one buffer per page (the fs block
+        * size == the page size), if one buffer needs block
+        * allocation or needs to modify the extent tree to clear the
+        * unwritten flag, we know that the page can't be written at
+        * all, so we might as well refuse the write immediately.
+        * Unfortunately if the block size != page size, we can't as
+        * easily detect this case using ext4_walk_page_buffers(), but
+        * for the extremely common case, this is an optimization that
+        * skips a useless round trip through ext4_bio_write_page().
         */
        if (ext4_walk_page_buffers(NULL, page_bufs, 0, len, NULL,
                                   ext4_bh_delay_or_unwritten)) {
                redirty_page_for_writepage(wbc, page);
-               if (current->flags & PF_MEMALLOC) {
+               if ((current->flags & PF_MEMALLOC) ||
+                   (inode->i_sb->s_blocksize == PAGE_CACHE_SIZE)) {
                        /*
                         * For memory cleaning there's no point in writing only
                         * some buffers. So just bail out. Warn if we came here
@@ -2599,8 +2642,7 @@ static int ext4_nonda_switch(struct super_block *sb)
 /* We always reserve for an inode update; the superblock could be there too */
 static int ext4_da_write_credits(struct inode *inode, loff_t pos, unsigned len)
 {
-       if (likely(EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
-                               EXT4_FEATURE_RO_COMPAT_LARGE_FILE)))
+       if (likely(ext4_has_feature_large_file(inode->i_sb)))
                return 1;
 
        if (pos + len <= 0x7fffffffULL)
@@ -3393,7 +3435,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,
                        /* We expect the key to be set. */
                        BUG_ON(!ext4_has_encryption_key(inode));
                        BUG_ON(blocksize != PAGE_CACHE_SIZE);
-                       WARN_ON_ONCE(ext4_decrypt_one(inode, page));
+                       WARN_ON_ONCE(ext4_decrypt(page));
                }
        }
        if (ext4_should_journal_data(inode)) {
@@ -3820,7 +3862,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
 
        iloc->bh = NULL;
        if (!ext4_valid_inum(sb, inode->i_ino))
-               return -EIO;
+               return -EFSCORRUPTED;
 
        iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
        gdp = ext4_get_group_desc(sb, iloc->block_group, NULL);
@@ -4006,8 +4048,7 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
        struct inode *inode = &(ei->vfs_inode);
        struct super_block *sb = inode->i_sb;
 
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+       if (ext4_has_feature_huge_file(sb)) {
                /* we are using combined 48 bit field */
                i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
                                        le32_to_cpu(raw_inode->i_blocks_lo);
@@ -4068,7 +4109,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)",
                                EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize,
                                EXT4_INODE_SIZE(inode->i_sb));
-                       ret = -EIO;
+                       ret = -EFSCORRUPTED;
                        goto bad_inode;
                }
        } else
@@ -4088,7 +4129,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 
        if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
                EXT4_ERROR_INODE(inode, "checksum invalid");
-               ret = -EIO;
+               ret = -EFSBADCRC;
                goto bad_inode;
        }
 
@@ -4130,7 +4171,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        ei->i_flags = le32_to_cpu(raw_inode->i_flags);
        inode->i_blocks = ext4_inode_blocks(raw_inode, ei);
        ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo);
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT))
+       if (ext4_has_feature_64bit(sb))
                ei->i_file_acl |=
                        ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
        inode->i_size = ext4_isize(raw_inode);
@@ -4203,7 +4244,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
            !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) {
                EXT4_ERROR_INODE(inode, "bad extended attribute block %llu",
                                 ei->i_file_acl);
-               ret = -EIO;
+               ret = -EFSCORRUPTED;
                goto bad_inode;
        } else if (!ext4_has_inline_data(inode)) {
                if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
@@ -4254,7 +4295,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        } else if (ino == EXT4_BOOT_LOADER_INO) {
                make_bad_inode(inode);
        } else {
-               ret = -EIO;
+               ret = -EFSCORRUPTED;
                EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode);
                goto bad_inode;
        }
@@ -4272,7 +4313,7 @@ bad_inode:
 struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino)
 {
        if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-EFSCORRUPTED);
        return ext4_iget(sb, ino);
 }
 
@@ -4294,7 +4335,7 @@ static int ext4_inode_blocks_set(handle_t *handle,
                ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
                return 0;
        }
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
+       if (!ext4_has_feature_huge_file(sb))
                return -EFBIG;
 
        if (i_blocks <= 0xffffffffffffULL) {
@@ -4455,8 +4496,7 @@ static int ext4_do_update_inode(handle_t *handle,
                need_datasync = 1;
        }
        if (ei->i_disksize > 0x7fffffffULL) {
-               if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
+               if (!ext4_has_feature_large_file(sb) ||
                                EXT4_SB(sb)->s_es->s_rev_level ==
                    cpu_to_le32(EXT4_GOOD_OLD_REV))
                        set_large_file = 1;
@@ -4505,8 +4545,7 @@ static int ext4_do_update_inode(handle_t *handle,
                if (err)
                        goto out_brelse;
                ext4_update_dynamic_rev(sb);
-               EXT4_SET_RO_COMPAT_FEATURE(sb,
-                                          EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
+               ext4_set_feature_large_file(sb);
                ext4_handle_sync(handle);
                err = ext4_handle_dirty_super(handle, sb);
        }
index 1346cfa355d0f167837a68d08325fa3529ebbc31..5e872fd40e5e38655435fbcf91802244c9ce8959 100644 (file)
@@ -145,8 +145,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
                inode_bl->i_version = 1;
                i_size_write(inode_bl, 0);
                inode_bl->i_mode = S_IFREG;
-               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                             EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+               if (ext4_has_feature_extents(sb)) {
                        ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS);
                        ext4_ext_tree_init(handle, inode_bl);
                } else
@@ -383,8 +382,7 @@ setversion_out:
                        goto group_extend_out;
                }
 
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                              EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+               if (ext4_has_feature_bigalloc(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online resizing not supported with bigalloc");
                        err = -EOPNOTSUPP;
@@ -432,8 +430,7 @@ group_extend_out:
                        goto mext_out;
                }
 
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                              EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+               if (ext4_has_feature_bigalloc(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online defrag not supported with bigalloc");
                        err = -EOPNOTSUPP;
@@ -470,8 +467,7 @@ mext_out:
                        goto group_add_out;
                }
 
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                              EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+               if (ext4_has_feature_bigalloc(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online resizing not supported with bigalloc");
                        err = -EOPNOTSUPP;
@@ -553,8 +549,7 @@ group_add_out:
                int err = 0, err2 = 0;
                ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
 
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                              EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+               if (ext4_has_feature_bigalloc(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online resizing not (yet) supported with bigalloc");
                        return -EOPNOTSUPP;
index 34b610ea503053674b3b87ffd3503d6c641c573d..b4b3c1f9181484767c0d812d262f57e115d91991 100644 (file)
@@ -874,8 +874,10 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        bh[i] = NULL;
                        continue;
                }
-               if (!(bh[i] = ext4_read_block_bitmap_nowait(sb, group))) {
-                       err = -ENOMEM;
+               bh[i] = ext4_read_block_bitmap_nowait(sb, group);
+               if (IS_ERR(bh[i])) {
+                       err = PTR_ERR(bh[i]);
+                       bh[i] = NULL;
                        goto out;
                }
                mb_debug(1, "read bitmap for group %u\n", group);
@@ -883,8 +885,13 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
        /* wait for I/O completion */
        for (i = 0, group = first_group; i < groups_per_page; i++, group++) {
-               if (bh[i] && ext4_wait_block_bitmap(sb, group, bh[i]))
-                       err = -EIO;
+               int err2;
+
+               if (!bh[i])
+                       continue;
+               err2 = ext4_wait_block_bitmap(sb, group, bh[i]);
+               if (!err)
+                       err = err2;
        }
 
        first_block = page->index * blocks_per_page;
@@ -2333,7 +2340,7 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
 
 }
 
-static const struct file_operations ext4_mb_seq_groups_fops = {
+const struct file_operations ext4_seq_mb_groups_fops = {
        .owner          = THIS_MODULE,
        .open           = ext4_mb_seq_groups_open,
        .read           = seq_read,
@@ -2447,7 +2454,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
                        kmalloc(sb->s_blocksize, GFP_NOFS);
                BUG_ON(meta_group_info[i]->bb_bitmap == NULL);
                bh = ext4_read_block_bitmap(sb, group);
-               BUG_ON(bh == NULL);
+               BUG_ON(IS_ERR_OR_NULL(bh));
                memcpy(meta_group_info[i]->bb_bitmap, bh->b_data,
                        sb->s_blocksize);
                put_bh(bh);
@@ -2661,10 +2668,6 @@ int ext4_mb_init(struct super_block *sb)
        if (ret != 0)
                goto out_free_locality_groups;
 
-       if (sbi->s_proc)
-               proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
-                                &ext4_mb_seq_groups_fops, sb);
-
        return 0;
 
 out_free_locality_groups:
@@ -2705,9 +2708,6 @@ int ext4_mb_release(struct super_block *sb)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
 
-       if (sbi->s_proc)
-               remove_proc_entry("mb_groups", sbi->s_proc);
-
        if (sbi->s_group_info) {
                for (i = 0; i < ngroups; i++) {
                        grinfo = ext4_get_group_info(sb, i);
@@ -2896,10 +2896,12 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        sb = ac->ac_sb;
        sbi = EXT4_SB(sb);
 
-       err = -EIO;
        bitmap_bh = ext4_read_block_bitmap(sb, ac->ac_b_ex.fe_group);
-       if (!bitmap_bh)
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               bitmap_bh = NULL;
                goto out_err;
+       }
 
        BUFFER_TRACE(bitmap_bh, "getting write access");
        err = ext4_journal_get_write_access(handle, bitmap_bh);
@@ -3331,8 +3333,8 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
                atomic_inc(&pa->pa_count);
                return pa;
        }
-       cur_distance = abs(goal_block - cpa->pa_pstart);
-       new_distance = abs(goal_block - pa->pa_pstart);
+       cur_distance = abs64(goal_block - cpa->pa_pstart);
+       new_distance = abs64(goal_block - pa->pa_pstart);
 
        if (cur_distance <= new_distance)
                return cpa;
@@ -3843,8 +3845,10 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
                return 0;
 
        bitmap_bh = ext4_read_block_bitmap(sb, group);
-       if (bitmap_bh == NULL) {
-               ext4_error(sb, "Error reading block bitmap for %u", group);
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               ext4_error(sb, "Error %d reading block bitmap for %u",
+                          err, group);
                return 0;
        }
 
@@ -4015,9 +4019,10 @@ repeat:
                }
 
                bitmap_bh = ext4_read_block_bitmap(sb, group);
-               if (bitmap_bh == NULL) {
-                       ext4_error(sb, "Error reading block bitmap for %u",
-                                       group);
+               if (IS_ERR(bitmap_bh)) {
+                       err = PTR_ERR(bitmap_bh);
+                       ext4_error(sb, "Error %d reading block bitmap for %u",
+                                       err, group);
                        ext4_mb_unload_buddy(&e4b);
                        continue;
                }
@@ -4682,22 +4687,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
        ext4_debug("freeing block %llu\n", block);
        trace_ext4_free_blocks(inode, block, count, flags);
 
-       if (flags & EXT4_FREE_BLOCKS_FORGET) {
-               struct buffer_head *tbh = bh;
-               int i;
-
-               BUG_ON(bh && (count > 1));
+       if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
+               BUG_ON(count > 1);
 
-               for (i = 0; i < count; i++) {
-                       cond_resched();
-                       if (!bh)
-                               tbh = sb_find_get_block(inode->i_sb,
-                                                       block + i);
-                       if (!tbh)
-                               continue;
-                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
-                                   inode, tbh, block + i);
-               }
+               ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
+                           inode, bh, block);
        }
 
        /*
@@ -4742,6 +4736,19 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
                        count += sbi->s_cluster_ratio - overflow;
        }
 
+       if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       cond_resched();
+                       bh = sb_find_get_block(inode->i_sb, block + i);
+                       if (!bh)
+                               continue;
+                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
+                                   inode, bh, block + i);
+               }
+       }
+
 do_more:
        overflow = 0;
        ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
@@ -4761,8 +4768,9 @@ do_more:
        }
        count_clusters = EXT4_NUM_B2C(sbi, count);
        bitmap_bh = ext4_read_block_bitmap(sb, block_group);
-       if (!bitmap_bh) {
-               err = -EIO;
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               bitmap_bh = NULL;
                goto error_return;
        }
        gdp = ext4_get_group_desc(sb, block_group, &gd_bh);
@@ -4931,8 +4939,9 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
        }
 
        bitmap_bh = ext4_read_block_bitmap(sb, block_group);
-       if (!bitmap_bh) {
-               err = -EIO;
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               bitmap_bh = NULL;
                goto error_return;
        }
 
index 6163ad21cb0ef6b184bdfceb700c1dfd89317590..a4651894cc3320b04e63cc3d296179be046d4da5 100644 (file)
@@ -448,8 +448,7 @@ int ext4_ext_migrate(struct inode *inode)
         * If the filesystem does not support extents, or the inode
         * already is extent-based, error out.
         */
-       if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
-                                      EXT4_FEATURE_INCOMPAT_EXTENTS) ||
+       if (!ext4_has_feature_extents(inode->i_sb) ||
            (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EINVAL;
 
@@ -625,13 +624,11 @@ int ext4_ind_migrate(struct inode *inode)
        handle_t                        *handle;
        int                             ret;
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
-                                      EXT4_FEATURE_INCOMPAT_EXTENTS) ||
+       if (!ext4_has_feature_extents(inode->i_sb) ||
            (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EINVAL;
 
-       if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
-                                      EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+       if (ext4_has_feature_bigalloc(inode->i_sb))
                return -EOPNOTSUPP;
 
        /*
index 6eb1a619890c580786f92a71c342a2eed41be973..0a512aa81bf7505ab8803cc90191249f91cb4a27 100644 (file)
@@ -98,10 +98,12 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
        }
 
        mmp = (struct mmp_struct *)((*bh)->b_data);
-       if (le32_to_cpu(mmp->mmp_magic) == EXT4_MMP_MAGIC &&
-           ext4_mmp_csum_verify(sb, mmp))
+       if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC)
+               ret = -EFSCORRUPTED;
+       else if (!ext4_mmp_csum_verify(sb, mmp))
+               ret = -EFSBADCRC;
+       else
                return 0;
-       ret = -EINVAL;
 
 warn_exit:
        ext4_warning(sb, "Error %d while reading MMP block %llu",
index 9f61e7679a6de53838a378a31f00bb5028b78877..a969ab39f3026187242dbea0881d5ebdb991d978 100644 (file)
@@ -109,7 +109,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
        if (!bh) {
                ext4_error_inode(inode, func, line, block,
                                 "Directory hole found");
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-EFSCORRUPTED);
        }
        dirent = (struct ext4_dir_entry *) bh->b_data;
        /* Determine whether or not we have an index block */
@@ -124,7 +124,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
        if (!is_dx_block && type == INDEX) {
                ext4_error_inode(inode, func, line, block,
                       "directory leaf block found instead of index block");
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-EFSCORRUPTED);
        }
        if (!ext4_has_metadata_csum(inode->i_sb) ||
            buffer_verified(bh))
@@ -142,7 +142,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
                        ext4_error_inode(inode, func, line, block,
                                         "Directory index failed checksum");
                        brelse(bh);
-                       return ERR_PTR(-EIO);
+                       return ERR_PTR(-EFSBADCRC);
                }
        }
        if (!is_dx_block) {
@@ -152,7 +152,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
                        ext4_error_inode(inode, func, line, block,
                                         "Directory block failed checksum");
                        brelse(bh);
-                       return ERR_PTR(-EIO);
+                       return ERR_PTR(-EFSBADCRC);
                }
        }
        return bh;
@@ -1429,7 +1429,7 @@ restart:
                                }
                                num++;
                                bh = ext4_getblk(NULL, dir, b++, 0);
-                               if (unlikely(IS_ERR(bh))) {
+                               if (IS_ERR(bh)) {
                                        if (ra_max == 0) {
                                                ret = bh;
                                                goto cleanup_and_exit;
@@ -1570,19 +1570,19 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                brelse(bh);
                if (!ext4_valid_inum(dir->i_sb, ino)) {
                        EXT4_ERROR_INODE(dir, "bad inode number: %u", ino);
-                       return ERR_PTR(-EIO);
+                       return ERR_PTR(-EFSCORRUPTED);
                }
                if (unlikely(ino == dir->i_ino)) {
                        EXT4_ERROR_INODE(dir, "'%pd' linked to parent dir",
                                         dentry);
-                       return ERR_PTR(-EIO);
+                       return ERR_PTR(-EFSCORRUPTED);
                }
                inode = ext4_iget_normal(dir->i_sb, ino);
                if (inode == ERR_PTR(-ESTALE)) {
                        EXT4_ERROR_INODE(dir,
                                         "deleted inode referenced: %u",
                                         ino);
-                       return ERR_PTR(-EIO);
+                       return ERR_PTR(-EFSCORRUPTED);
                }
                if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
                    (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
@@ -1619,7 +1619,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
        if (!ext4_valid_inum(d_inode(child)->i_sb, ino)) {
                EXT4_ERROR_INODE(d_inode(child),
                                 "bad parent inode number: %u", ino);
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-EFSCORRUPTED);
        }
 
        return d_obtain_alias(ext4_iget_normal(d_inode(child)->i_sb, ino));
@@ -1807,7 +1807,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
        while ((char *) de <= top) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
                                         buf, buf_size, offset)) {
-                       res = -EIO;
+                       res = -EFSCORRUPTED;
                        goto return_result;
                }
                /* Provide crypto context and crypto buffer to ext4 match */
@@ -1967,7 +1967,7 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
        if ((char *) de >= (((char *) root) + blocksize)) {
                EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
                brelse(bh);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        len = ((char *) root) + (blocksize - csum_size) - (char *) de;
 
@@ -2118,7 +2118,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                        goto out;
 
                if (blocks == 1 && !dx_fallback &&
-                   EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+                   ext4_has_feature_dir_index(sb)) {
                        retval = make_indexed_dir(handle, &fname, dentry,
                                                  inode, bh);
                        bh = NULL; /* make_indexed_dir releases bh */
@@ -2315,7 +2315,7 @@ int ext4_generic_delete_entry(handle_t *handle,
        while (i < buf_size - csum_size) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
                                         bh->b_data, bh->b_size, i))
-                       return -EIO;
+                       return -EFSCORRUPTED;
                if (de == de_del)  {
                        if (pde)
                                pde->rec_len = ext4_rec_len_to_disk(
@@ -2388,8 +2388,7 @@ static void ext4_inc_count(handle_t *handle, struct inode *inode)
                /* limit is 16-bit i_links_count */
                if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
                        set_nlink(inode, 1);
-                       EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
-                                             EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
+                       ext4_set_feature_dir_nlink(inode->i_sb);
                }
        }
 }
@@ -2469,9 +2468,6 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
        struct inode *inode;
        int err, credits, retries = 0;
 
-       if (!new_valid_dev(rdev))
-               return -EINVAL;
-
        err = dquot_initialize(dir);
        if (err)
                return err;
@@ -2934,7 +2930,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 
        inode = d_inode(dentry);
 
-       retval = -EIO;
+       retval = -EFSCORRUPTED;
        if (le32_to_cpu(de->inode) != inode->i_ino)
                goto end_rmdir;
 
@@ -3008,7 +3004,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 
        inode = d_inode(dentry);
 
-       retval = -EIO;
+       retval = -EFSCORRUPTED;
        if (le32_to_cpu(de->inode) != inode->i_ino)
                goto end_unlink;
 
@@ -3310,7 +3306,7 @@ static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent)
        if (!ent->dir_bh)
                return retval;
        if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino)
-               return -EIO;
+               return -EFSCORRUPTED;
        BUFFER_TRACE(ent->dir_bh, "get_write_access");
        return ext4_journal_get_write_access(handle, ent->dir_bh);
 }
@@ -3352,8 +3348,7 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
        if (retval)
                return retval;
        ent->de->inode = cpu_to_le32(ino);
-       if (EXT4_HAS_INCOMPAT_FEATURE(ent->dir->i_sb,
-                                     EXT4_FEATURE_INCOMPAT_FILETYPE))
+       if (ext4_has_feature_filetype(ent->dir->i_sb))
                ent->de->file_type = file_type;
        ent->dir->i_version++;
        ent->dir->i_ctime = ent->dir->i_mtime =
index 84ba4d2b3a35f58158b8e1c49b57ed74d806c569..17fbe3882b8eb70e3ecc0445a950d25b42423beb 100644 (file)
@@ -425,6 +425,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
        struct buffer_head *bh, *head;
        int ret = 0;
        int nr_submitted = 0;
+       int nr_to_submit = 0;
 
        blocksize = 1 << inode->i_blkbits;
 
@@ -477,11 +478,13 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
                        unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
                }
                set_buffer_async_write(bh);
+               nr_to_submit++;
        } while ((bh = bh->b_this_page) != head);
 
        bh = head = page_buffers(page);
 
-       if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
+       if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) &&
+           nr_to_submit) {
                data_page = ext4_encrypt(inode, page);
                if (IS_ERR(data_page)) {
                        ret = PTR_ERR(data_page);
index 1061611ae14dd6c66878584820528d757cfea399..5dc5e95063de2a7e42749a94464f00f7c50be4b8 100644 (file)
@@ -62,7 +62,7 @@ static void completion_pages(struct work_struct *work)
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
 
-               int ret = ext4_decrypt(ctx, page);
+               int ret = ext4_decrypt(page);
                if (ret) {
                        WARN_ON_ONCE(1);
                        SetPageError(page);
index cf0c472047e3a89a84e262c7eeddd7ca72fd1b8c..ad62d7acc31578df85c3b97ac7839295a4454008 100644 (file)
@@ -490,7 +490,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
               group_data[0].group != sbi->s_groups_count);
 
        reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks);
-       meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG);
+       meta_bg = ext4_has_feature_meta_bg(sb);
 
        /* This transaction may be extended/restarted along the way */
        handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, EXT4_MAX_TRANS_DATA);
@@ -680,8 +680,7 @@ static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,
        int mult = 3;
        unsigned ret;
 
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+       if (!ext4_has_feature_sparse_super(sb)) {
                ret = *min;
                *min += 1;
                return ret;
@@ -1040,7 +1039,7 @@ exit_free:
  * do not copy the full number of backups at this time.  The resize
  * which changed s_groups_count will backup again.
  */
-static void update_backups(struct super_block *sb, int blk_off, char *data,
+static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
                           int size, int meta_bg)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1065,7 +1064,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data,
                group = ext4_list_backups(sb, &three, &five, &seven);
                last = sbi->s_groups_count;
        } else {
-               group = ext4_meta_bg_first_group(sb, group) + 1;
+               group = ext4_get_group_number(sb, blk_off) + 1;
                last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2);
        }
 
@@ -1158,7 +1157,7 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb,
        int i, gdb_off, gdb_num, err = 0;
        int meta_bg;
 
-       meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG);
+       meta_bg = ext4_has_feature_meta_bg(sb);
        for (i = 0; i < count; i++, group++) {
                int reserved_gdb = ext4_bg_has_super(sb, group) ?
                        le16_to_cpu(es->s_reserved_gdt_blocks) : 0;
@@ -1381,9 +1380,7 @@ static void ext4_update_super(struct super_block *sb,
 
        ext4_debug("free blocks count %llu",
                   percpu_counter_read(&sbi->s_freeclusters_counter));
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                     EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
-           sbi->s_log_groups_per_flex) {
+       if (ext4_has_feature_flex_bg(sb) && sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group;
                flex_group = ext4_flex_group(sbi, group_data[0].group);
                atomic64_add(EXT4_NUM_B2C(sbi, free_blocks),
@@ -1476,8 +1473,7 @@ exit_journal:
                int gdb_num = group / EXT4_DESC_PER_BLOCK(sb);
                int gdb_num_end = ((group + flex_gd->count - 1) /
                                   EXT4_DESC_PER_BLOCK(sb));
-               int meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb,
-                               EXT4_FEATURE_INCOMPAT_META_BG);
+               int meta_bg = ext4_has_feature_meta_bg(sb);
                sector_t old_gdb = 0;
 
                update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
@@ -1585,8 +1581,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
 
        gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb);
 
-       if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+       if (gdb_off == 0 && !ext4_has_feature_sparse_super(sb)) {
                ext4_warning(sb, "Can't resize non-sparse filesystem further");
                return -EPERM;
        }
@@ -1604,9 +1599,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        }
 
        if (reserved_gdb || gdb_off == 0) {
-               if (!EXT4_HAS_COMPAT_FEATURE(sb,
-                                            EXT4_FEATURE_COMPAT_RESIZE_INODE)
-                   || !le16_to_cpu(es->s_reserved_gdt_blocks)) {
+               if (ext4_has_feature_resize_inode(sb) ||
+                   !le16_to_cpu(es->s_reserved_gdt_blocks)) {
                        ext4_warning(sb,
                                     "No reserved GDT blocks, can't resize");
                        return -EPERM;
@@ -1825,8 +1819,8 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode)
        if (err)
                goto errout;
 
-       EXT4_CLEAR_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE);
-       EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG);
+       ext4_clear_feature_resize_inode(sb);
+       ext4_set_feature_meta_bg(sb);
        sbi->s_es->s_first_meta_bg =
                cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count));
 
@@ -1918,9 +1912,9 @@ retry:
        n_desc_blocks = num_desc_blocks(sb, n_group + 1);
        o_desc_blocks = num_desc_blocks(sb, sbi->s_groups_count);
 
-       meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG);
+       meta_bg = ext4_has_feature_meta_bg(sb);
 
-       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE)) {
+       if (ext4_has_feature_resize_inode(sb)) {
                if (meta_bg) {
                        ext4_error(sb, "resize_inode and meta_bg enabled "
                                   "simultaneously");
index 49f6c78ee3afe26aa45941d443c5ea242ef95676..753f4e68b820da0dd78fc7a7e3a66e529846ea0b 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
-#include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/ext4.h>
 
-static struct proc_dir_entry *ext4_proc_root;
-static struct kset *ext4_kset;
 static struct ext4_lazy_init *ext4_li_info;
 static struct mutex ext4_li_mtx;
-static struct ext4_features *ext4_feat;
 static int ext4_mballoc_ready;
 static struct ratelimit_state ext4_mount_msg_ratelimit;
 
@@ -83,7 +79,6 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly);
 static void ext4_destroy_lazyinit_thread(void);
 static void ext4_unregister_li_request(struct super_block *sb);
 static void ext4_clear_request_list(void);
-static int ext4_reserve_clusters(struct ext4_sb_info *, ext4_fsblk_t);
 
 #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2)
 static struct file_system_type ext2_fs_type = {
@@ -115,8 +110,7 @@ MODULE_ALIAS("ext3");
 static int ext4_verify_csum_type(struct super_block *sb,
                                 struct ext4_super_block *es)
 {
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+       if (!ext4_has_feature_metadata_csum(sb))
                return 1;
 
        return es->s_checksum_type == EXT4_CRC32C_CHKSUM;
@@ -394,9 +388,13 @@ static void ext4_handle_error(struct super_block *sb)
                smp_wmb();
                sb->s_flags |= MS_RDONLY;
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs (device %s): panic forced after error\n",
                        sb->s_id);
+       }
 }
 
 #define ext4_error_ratelimit(sb)                                       \
@@ -495,6 +493,12 @@ const char *ext4_decode_error(struct super_block *sb, int errno,
        char *errstr = NULL;
 
        switch (errno) {
+       case -EFSCORRUPTED:
+               errstr = "Corrupt filesystem";
+               break;
+       case -EFSBADCRC:
+               errstr = "Filesystem failed CRC";
+               break;
        case -EIO:
                errstr = "IO failure";
                break;
@@ -585,8 +589,12 @@ void __ext4_abort(struct super_block *sb, const char *function,
                        jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
                save_error_info(sb, function, line);
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs panic from previous error\n");
+       }
 }
 
 void __ext4_msg(struct super_block *sb,
@@ -800,6 +808,7 @@ static void ext4_put_super(struct super_block *sb)
                        ext4_abort(sb, "Couldn't clean up the journal");
        }
 
+       ext4_unregister_sysfs(sb);
        ext4_es_unregister_shrinker(sbi);
        del_timer_sync(&sbi->s_err_report);
        ext4_release_system_zone(sb);
@@ -808,18 +817,12 @@ static void ext4_put_super(struct super_block *sb)
        ext4_xattr_put_super(sb);
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
        }
        if (!(sb->s_flags & MS_RDONLY))
                ext4_commit_super(sb, 1);
 
-       if (sbi->s_proc) {
-               remove_proc_entry("options", sbi->s_proc);
-               remove_proc_entry(sb->s_id, ext4_proc_root);
-       }
-       kobject_del(&sbi->s_kobj);
-
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
        kvfree(sbi->s_group_desc);
@@ -1288,7 +1291,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
                        "quota options when quota turned on");
                return -1;
        }
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+       if (ext4_has_feature_quota(sb)) {
                ext4_msg(sb, KERN_ERR, "Cannot set journaled quota options "
                         "when QUOTA feature is enabled");
                return -1;
@@ -1381,10 +1384,10 @@ static const struct mount_opts {
        {Opt_nojournal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
         MOPT_EXT4_ONLY | MOPT_CLEAR},
        {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
-        MOPT_EXT4_ONLY | MOPT_SET},
+        MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
        {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
                                    EXT4_MOUNT_JOURNAL_CHECKSUM),
-        MOPT_EXT4_ONLY | MOPT_SET},
+        MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
        {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | MOPT_SET},
        {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR},
        {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
@@ -1513,8 +1516,14 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                return -1;
        if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
                return -1;
-       if (m->flags & MOPT_EXPLICIT)
-               set_opt2(sb, EXPLICIT_DELALLOC);
+       if (m->flags & MOPT_EXPLICIT) {
+               if (m->mount_opt & EXT4_MOUNT_DELALLOC) {
+                       set_opt2(sb, EXPLICIT_DELALLOC);
+               } else if (m->mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) {
+                       set_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM);
+               } else
+                       return -1;
+       }
        if (m->flags & MOPT_CLEAR_ERR)
                clear_opt(sb, ERRORS_MASK);
        if (token == Opt_noquota && sb_any_quota_loaded(sb)) {
@@ -1647,8 +1656,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                                 "quota options when quota turned on");
                        return -1;
                }
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                              EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+               if (ext4_has_feature_quota(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Cannot set journaled quota options "
                                 "when QUOTA feature is enabled");
@@ -1707,7 +1715,7 @@ static int parse_options(char *options, struct super_block *sb,
                        return 0;
        }
 #ifdef CONFIG_QUOTA
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
+       if (ext4_has_feature_quota(sb) &&
            (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
                ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
                         "feature is enabled");
@@ -1880,7 +1888,7 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root)
        return _ext4_show_options(seq, root->d_sb, 0);
 }
 
-static int options_seq_show(struct seq_file *seq, void *offset)
+int ext4_seq_options_show(struct seq_file *seq, void *offset)
 {
        struct super_block *sb = seq->private;
        int rc;
@@ -1891,19 +1899,6 @@ static int options_seq_show(struct seq_file *seq, void *offset)
        return rc;
 }
 
-static int options_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, options_seq_show, PDE_DATA(inode));
-}
-
-static const struct file_operations ext4_seq_options_fops = {
-       .owner = THIS_MODULE,
-       .open = options_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
 static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                            int read_only)
 {
@@ -1944,7 +1939,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        es->s_mtime = cpu_to_le32(get_seconds());
        ext4_update_dynamic_rev(sb);
        if (sbi->s_journal)
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_set_feature_journal_needs_recovery(sb);
 
        ext4_commit_super(sb, 1);
 done:
@@ -2027,12 +2022,13 @@ failed:
        return 0;
 }
 
-static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
+static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
                                   struct ext4_group_desc *gdp)
 {
        int offset;
        __u16 crc = 0;
        __le32 le_group = cpu_to_le32(block_group);
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (ext4_has_metadata_csum(sbi->s_sb)) {
                /* Use new metadata_csum algorithm */
@@ -2052,8 +2048,7 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
        }
 
        /* old crc16 code */
-       if (!(sbi->s_es->s_feature_ro_compat &
-             cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
+       if (!ext4_has_feature_gdt_csum(sb))
                return 0;
 
        offset = offsetof(struct ext4_group_desc, bg_checksum);
@@ -2063,8 +2058,7 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
        crc = crc16(crc, (__u8 *)gdp, offset);
        offset += sizeof(gdp->bg_checksum); /* skip checksum */
        /* for checksum of struct ext4_group_desc do the rest...*/
-       if ((sbi->s_es->s_feature_incompat &
-            cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
+       if (ext4_has_feature_64bit(sb) &&
            offset < le16_to_cpu(sbi->s_es->s_desc_size))
                crc = crc16(crc, (__u8 *)gdp + offset,
                            le16_to_cpu(sbi->s_es->s_desc_size) -
@@ -2078,8 +2072,7 @@ int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
                                struct ext4_group_desc *gdp)
 {
        if (ext4_has_group_desc_csum(sb) &&
-           (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb),
-                                                     block_group, gdp)))
+           (gdp->bg_checksum != ext4_group_desc_csum(sb, block_group, gdp)))
                return 0;
 
        return 1;
@@ -2090,7 +2083,7 @@ void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
 {
        if (!ext4_has_group_desc_csum(sb))
                return;
-       gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp);
+       gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp);
 }
 
 /* Called at mount-time, super-block is locked */
@@ -2106,7 +2099,7 @@ static int ext4_check_descriptors(struct super_block *sb,
        int flexbg_flag = 0;
        ext4_group_t i, grp = sbi->s_groups_count;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+       if (ext4_has_feature_flex_bg(sb))
                flexbg_flag = 1;
 
        ext4_debug("Checking group descriptors");
@@ -2150,7 +2143,7 @@ static int ext4_check_descriptors(struct super_block *sb,
                if (!ext4_group_desc_csum_verify(sb, i, gdp)) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                                 "Checksum for group %u failed (%u!=%u)",
-                                i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+                                i, le16_to_cpu(ext4_group_desc_csum(sb, i,
                                     gdp)), le16_to_cpu(gdp->bg_checksum));
                        if (!(sb->s_flags & MS_RDONLY)) {
                                ext4_unlock_group(sb, i);
@@ -2413,8 +2406,7 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
 
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
-           nr < first_meta_bg)
+       if (!ext4_has_feature_meta_bg(sb) || nr < first_meta_bg)
                return logical_sb_block + nr + 1;
        bg = sbi->s_desc_per_block * nr;
        if (ext4_bg_has_super(sb, bg))
@@ -2470,335 +2462,6 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
        return ret;
 }
 
-/* sysfs supprt */
-
-struct ext4_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
-       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *,
-                        const char *, size_t);
-       union {
-               int offset;
-               int deprecated_val;
-       } u;
-};
-
-static int parse_strtoull(const char *buf,
-               unsigned long long max, unsigned long long *value)
-{
-       int ret;
-
-       ret = kstrtoull(skip_spaces(buf), 0, value);
-       if (!ret && *value > max)
-               ret = -EINVAL;
-       return ret;
-}
-
-static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a,
-                                             struct ext4_sb_info *sbi,
-                                             char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (s64) EXT4_C2B(sbi,
-                       percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
-}
-
-static ssize_t session_write_kbytes_show(struct ext4_attr *a,
-                                        struct ext4_sb_info *sbi, char *buf)
-{
-       struct super_block *sb = sbi->s_buddy_cache->i_sb;
-
-       if (!sb->s_bdev->bd_part)
-               return snprintf(buf, PAGE_SIZE, "0\n");
-       return snprintf(buf, PAGE_SIZE, "%lu\n",
-                       (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
-                        sbi->s_sectors_written_start) >> 1);
-}
-
-static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
-                                         struct ext4_sb_info *sbi, char *buf)
-{
-       struct super_block *sb = sbi->s_buddy_cache->i_sb;
-
-       if (!sb->s_bdev->bd_part)
-               return snprintf(buf, PAGE_SIZE, "0\n");
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-                       (unsigned long long)(sbi->s_kbytes_written +
-                       ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
-                         EXT4_SB(sb)->s_sectors_written_start) >> 1)));
-}
-
-static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
-                                         struct ext4_sb_info *sbi,
-                                         const char *buf, size_t count)
-{
-       unsigned long t;
-       int ret;
-
-       ret = kstrtoul(skip_spaces(buf), 0, &t);
-       if (ret)
-               return ret;
-
-       if (t && (!is_power_of_2(t) || t > 0x40000000))
-               return -EINVAL;
-
-       sbi->s_inode_readahead_blks = t;
-       return count;
-}
-
-static ssize_t sbi_ui_show(struct ext4_attr *a,
-                          struct ext4_sb_info *sbi, char *buf)
-{
-       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset);
-
-       return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
-}
-
-static ssize_t sbi_ui_store(struct ext4_attr *a,
-                           struct ext4_sb_info *sbi,
-                           const char *buf, size_t count)
-{
-       unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset);
-       unsigned long t;
-       int ret;
-
-       ret = kstrtoul(skip_spaces(buf), 0, &t);
-       if (ret)
-               return ret;
-       *ui = t;
-       return count;
-}
-
-static ssize_t es_ui_show(struct ext4_attr *a,
-                          struct ext4_sb_info *sbi, char *buf)
-{
-
-       unsigned int *ui = (unsigned int *) (((char *) sbi->s_es) +
-                          a->u.offset);
-
-       return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
-}
-
-static ssize_t reserved_clusters_show(struct ext4_attr *a,
-                                 struct ext4_sb_info *sbi, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%llu\n",
-               (unsigned long long) atomic64_read(&sbi->s_resv_clusters));
-}
-
-static ssize_t reserved_clusters_store(struct ext4_attr *a,
-                                  struct ext4_sb_info *sbi,
-                                  const char *buf, size_t count)
-{
-       unsigned long long val;
-       int ret;
-
-       if (parse_strtoull(buf, -1ULL, &val))
-               return -EINVAL;
-       ret = ext4_reserve_clusters(sbi, val);
-
-       return ret ? ret : count;
-}
-
-static ssize_t trigger_test_error(struct ext4_attr *a,
-                                 struct ext4_sb_info *sbi,
-                                 const char *buf, size_t count)
-{
-       int len = count;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (len && buf[len-1] == '\n')
-               len--;
-
-       if (len)
-               ext4_error(sbi->s_sb, "%.*s", len, buf);
-       return count;
-}
-
-static ssize_t sbi_deprecated_show(struct ext4_attr *a,
-                                  struct ext4_sb_info *sbi, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d\n", a->u.deprecated_val);
-}
-
-#define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \
-static struct ext4_attr ext4_attr_##_name = {                  \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-       .u = {                                                  \
-               .offset = offsetof(struct ext4_sb_info, _elname),\
-       },                                                      \
-}
-
-#define EXT4_ATTR_OFFSET_ES(_name,_mode,_show,_store,_elname)          \
-static struct ext4_attr ext4_attr_##_name = {                          \
-       .attr = {.name = __stringify(_name), .mode = _mode },           \
-       .show   = _show,                                                \
-       .store  = _store,                                               \
-       .u = {                                                          \
-               .offset = offsetof(struct ext4_super_block, _elname),   \
-       },                                                              \
-}
-
-#define EXT4_ATTR(name, mode, show, store) \
-static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
-
-#define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL)
-#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
-#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
-
-#define EXT4_RO_ATTR_ES_UI(name, elname)       \
-       EXT4_ATTR_OFFSET_ES(name, 0444, es_ui_show, NULL, elname)
-#define EXT4_RW_ATTR_SBI_UI(name, elname)      \
-       EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname)
-
-#define ATTR_LIST(name) &ext4_attr_##name.attr
-#define EXT4_DEPRECATED_ATTR(_name, _val)      \
-static struct ext4_attr ext4_attr_##_name = {                  \
-       .attr = {.name = __stringify(_name), .mode = 0444 },    \
-       .show   = sbi_deprecated_show,                          \
-       .u = {                                                  \
-               .deprecated_val = _val,                         \
-       },                                                      \
-}
-
-EXT4_RO_ATTR(delayed_allocation_blocks);
-EXT4_RO_ATTR(session_write_kbytes);
-EXT4_RO_ATTR(lifetime_write_kbytes);
-EXT4_RW_ATTR(reserved_clusters);
-EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
-                inode_readahead_blks_store, s_inode_readahead_blks);
-EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
-EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
-EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
-EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
-EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
-EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
-EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
-EXT4_DEPRECATED_ATTR(max_writeback_mb_bump, 128);
-EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb);
-EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error);
-EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval);
-EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst);
-EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval);
-EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst);
-EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval);
-EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
-EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
-EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time);
-EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time);
-
-static struct attribute *ext4_attrs[] = {
-       ATTR_LIST(delayed_allocation_blocks),
-       ATTR_LIST(session_write_kbytes),
-       ATTR_LIST(lifetime_write_kbytes),
-       ATTR_LIST(reserved_clusters),
-       ATTR_LIST(inode_readahead_blks),
-       ATTR_LIST(inode_goal),
-       ATTR_LIST(mb_stats),
-       ATTR_LIST(mb_max_to_scan),
-       ATTR_LIST(mb_min_to_scan),
-       ATTR_LIST(mb_order2_req),
-       ATTR_LIST(mb_stream_req),
-       ATTR_LIST(mb_group_prealloc),
-       ATTR_LIST(max_writeback_mb_bump),
-       ATTR_LIST(extent_max_zeroout_kb),
-       ATTR_LIST(trigger_fs_error),
-       ATTR_LIST(err_ratelimit_interval_ms),
-       ATTR_LIST(err_ratelimit_burst),
-       ATTR_LIST(warning_ratelimit_interval_ms),
-       ATTR_LIST(warning_ratelimit_burst),
-       ATTR_LIST(msg_ratelimit_interval_ms),
-       ATTR_LIST(msg_ratelimit_burst),
-       ATTR_LIST(errors_count),
-       ATTR_LIST(first_error_time),
-       ATTR_LIST(last_error_time),
-       NULL,
-};
-
-/* Features this copy of ext4 supports */
-EXT4_INFO_ATTR(lazy_itable_init);
-EXT4_INFO_ATTR(batched_discard);
-EXT4_INFO_ATTR(meta_bg_resize);
-EXT4_INFO_ATTR(encryption);
-
-static struct attribute *ext4_feat_attrs[] = {
-       ATTR_LIST(lazy_itable_init),
-       ATTR_LIST(batched_discard),
-       ATTR_LIST(meta_bg_resize),
-       ATTR_LIST(encryption),
-       NULL,
-};
-
-static ssize_t ext4_attr_show(struct kobject *kobj,
-                             struct attribute *attr, char *buf)
-{
-       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
-                                               s_kobj);
-       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
-
-       return a->show ? a->show(a, sbi, buf) : 0;
-}
-
-static ssize_t ext4_attr_store(struct kobject *kobj,
-                              struct attribute *attr,
-                              const char *buf, size_t len)
-{
-       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
-                                               s_kobj);
-       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
-
-       return a->store ? a->store(a, sbi, buf, len) : 0;
-}
-
-static void ext4_sb_release(struct kobject *kobj)
-{
-       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
-                                               s_kobj);
-       complete(&sbi->s_kobj_unregister);
-}
-
-static const struct sysfs_ops ext4_attr_ops = {
-       .show   = ext4_attr_show,
-       .store  = ext4_attr_store,
-};
-
-static struct kobj_type ext4_ktype = {
-       .default_attrs  = ext4_attrs,
-       .sysfs_ops      = &ext4_attr_ops,
-       .release        = ext4_sb_release,
-};
-
-static void ext4_feat_release(struct kobject *kobj)
-{
-       complete(&ext4_feat->f_kobj_unregister);
-}
-
-static ssize_t ext4_feat_show(struct kobject *kobj,
-                             struct attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "supported\n");
-}
-
-/*
- * We can not use ext4_attr_show/store because it relies on the kobject
- * being embedded in the ext4_sb_info structure which is definitely not
- * true in this case.
- */
-static const struct sysfs_ops ext4_feat_ops = {
-       .show   = ext4_feat_show,
-       .store  = NULL,
-};
-
-static struct kobj_type ext4_feat_ktype = {
-       .default_attrs  = ext4_feat_attrs,
-       .sysfs_ops      = &ext4_feat_ops,
-       .release        = ext4_feat_release,
-};
-
 /*
  * Check whether this filesystem can be mounted based on
  * the features present and the RDONLY/RDWR mount requested.
@@ -2807,7 +2470,7 @@ static struct kobj_type ext4_feat_ktype = {
  */
 static int ext4_feature_set_ok(struct super_block *sb, int readonly)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
+       if (ext4_has_unknown_ext4_incompat_features(sb)) {
                ext4_msg(sb, KERN_ERR,
                        "Couldn't mount because of "
                        "unsupported optional features (%x)",
@@ -2819,14 +2482,14 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
        if (readonly)
                return 1;
 
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_READONLY)) {
+       if (ext4_has_feature_readonly(sb)) {
                ext4_msg(sb, KERN_INFO, "filesystem is read-only");
                sb->s_flags |= MS_RDONLY;
                return 1;
        }
 
        /* Check that feature set is OK for a read-write mount */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
+       if (ext4_has_unknown_ext4_ro_compat_features(sb)) {
                ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
                         "unsupported optional features (%x)",
                         (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) &
@@ -2837,7 +2500,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
         * Large file size enabled file system can only be mounted
         * read-write on 32-bit systems if kernel is built with CONFIG_LBDAF
         */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+       if (ext4_has_feature_huge_file(sb)) {
                if (sizeof(blkcnt_t) < sizeof(u64)) {
                        ext4_msg(sb, KERN_ERR, "Filesystem with huge files "
                                 "cannot be mounted RDWR without "
@@ -2845,8 +2508,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
                        return 0;
                }
        }
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
-           !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_bigalloc(sb) && !ext4_has_feature_extents(sb)) {
                ext4_msg(sb, KERN_ERR,
                         "Can't support bigalloc feature without "
                         "extents feature\n");
@@ -2854,8 +2516,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
        }
 
 #ifndef CONFIG_QUOTA
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
-           !readonly) {
+       if (ext4_has_feature_quota(sb) && !readonly) {
                ext4_msg(sb, KERN_ERR,
                         "Filesystem with quota feature cannot be mounted RDWR "
                         "without CONFIG_QUOTA");
@@ -3312,7 +2973,7 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp,
        ext4_group_t            i, ngroups = ext4_get_groups_count(sb);
        int                     s, j, count = 0;
 
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+       if (!ext4_has_feature_bigalloc(sb))
                return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) +
                        sbi->s_itb_per_group + 2);
 
@@ -3403,10 +3064,10 @@ int ext4_calculate_overhead(struct super_block *sb)
        return 0;
 }
 
-
-static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb)
+static void ext4_set_resv_clusters(struct super_block *sb)
 {
        ext4_fsblk_t resv_clusters;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        /*
         * There's no need to reserve anything when we aren't using extents.
@@ -3414,8 +3075,8 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb)
         * hole punching doesn't need new metadata... This is needed especially
         * to keep ext2/3 backward compatibility.
         */
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS))
-               return 0;
+       if (!ext4_has_feature_extents(sb))
+               return;
        /*
         * By default we reserve 2% or 4096 clusters, whichever is smaller.
         * This should cover the situations where we can not afford to run
@@ -3424,26 +3085,13 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb)
         * allocation would require 1, or 2 blocks, higher numbers are
         * very rare.
         */
-       resv_clusters = ext4_blocks_count(EXT4_SB(sb)->s_es) >>
-                       EXT4_SB(sb)->s_cluster_bits;
+       resv_clusters = (ext4_blocks_count(sbi->s_es) >>
+                        sbi->s_cluster_bits);
 
        do_div(resv_clusters, 50);
        resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096);
 
-       return resv_clusters;
-}
-
-
-static int ext4_reserve_clusters(struct ext4_sb_info *sbi, ext4_fsblk_t count)
-{
-       ext4_fsblk_t clusters = ext4_blocks_count(sbi->s_es) >>
-                               sbi->s_cluster_bits;
-
-       if (count >= clusters)
-               return -EINVAL;
-
-       atomic64_set(&sbi->s_resv_clusters, count);
-       return 0;
+       atomic64_set(&sbi->s_resv_clusters, resv_clusters);
 }
 
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
@@ -3526,9 +3174,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
 
        /* Warn if metadata_csum and gdt_csum are both set. */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
-           EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+       if (ext4_has_feature_metadata_csum(sb) &&
+           ext4_has_feature_gdt_csum(sb))
                ext4_warning(sb, "metadata_csum and uninit_bg are "
                             "redundant flags; please run fsck.");
 
@@ -3541,8 +3188,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* Load the checksum driver */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_has_feature_metadata_csum(sb)) {
                sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
                if (IS_ERR(sbi->s_chksum_driver)) {
                        ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
@@ -3557,11 +3203,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
                         "invalid superblock checksum.  Run e2fsck?");
                silent = 1;
+               ret = -EFSBADCRC;
                goto cantfind_ext4;
        }
 
        /* Precompute checksum seed for all metadata */
-       if (ext4_has_metadata_csum(sb))
+       if (ext4_has_feature_csum_seed(sb))
+               sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed);
+       else if (ext4_has_metadata_csum(sb))
                sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
                                               sizeof(es->s_uuid));
 
@@ -3664,17 +3313,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
-           (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
-            EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
-            EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U)))
+           (ext4_has_compat_features(sb) ||
+            ext4_has_ro_compat_features(sb) ||
+            ext4_has_incompat_features(sb)))
                ext4_msg(sb, KERN_WARNING,
                       "feature flags set on rev 0 fs, "
                       "running e2fsck is recommended");
 
        if (es->s_creator_os == cpu_to_le32(EXT4_OS_HURD)) {
                set_opt2(sb, HURD_COMPAT);
-               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                             EXT4_FEATURE_INCOMPAT_64BIT)) {
+               if (ext4_has_feature_64bit(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "The Hurd can't support 64-bit file systems");
                        goto failed_mount;
@@ -3732,8 +3380,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT) &&
-           es->s_encryption_level) {
+       if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) {
                ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
                         es->s_encryption_level);
                goto failed_mount;
@@ -3765,8 +3412,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
+       has_huge_files = ext4_has_feature_huge_file(sb);
        sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits,
                                                      has_huge_files);
        sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files);
@@ -3790,7 +3436,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
+       if (ext4_has_feature_64bit(sb)) {
                if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
                    sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
                    !is_power_of_2(sbi->s_desc_size)) {
@@ -3821,7 +3467,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        for (i = 0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
-       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+       if (ext4_has_feature_dir_index(sb)) {
                i = le32_to_cpu(es->s_flags);
                if (i & EXT2_FLAGS_UNSIGNED_HASH)
                        sbi->s_hash_unsigned = 3;
@@ -3841,8 +3487,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
        /* Handle clustersize */
        clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size);
-       has_bigalloc = EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_BIGALLOC);
+       has_bigalloc = ext4_has_feature_bigalloc(sb);
        if (has_bigalloc) {
                if (clustersize < blocksize) {
                        ext4_msg(sb, KERN_ERR,
@@ -3961,13 +3606,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
-       if (ext4_proc_root)
-               sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
-
-       if (sbi->s_proc)
-               proc_create_data("options", S_IRUGO, sbi->s_proc,
-                                &ext4_seq_options_fops, sb);
-
        bgl_lock_init(sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
@@ -3982,6 +3620,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
                ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
+               ret = -EFSCORRUPTED;
                goto failed_mount2;
        }
 
@@ -4007,7 +3646,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ext4_xattr_handlers;
 #ifdef CONFIG_QUOTA
        sb->dq_op = &ext4_quota_operations;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
+       if (ext4_has_feature_quota(sb))
                sb->s_qcop = &dquot_quotactl_sysfile_ops;
        else
                sb->s_qcop = &ext4_qctl_operations;
@@ -4021,11 +3660,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_root = NULL;
 
        needs_recovery = (es->s_last_orphan != 0 ||
-                         EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                   EXT4_FEATURE_INCOMPAT_RECOVER));
+                         ext4_has_feature_journal_needs_recovery(sb));
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
-           !(sb->s_flags & MS_RDONLY))
+       if (ext4_has_feature_mmp(sb) && !(sb->s_flags & MS_RDONLY))
                if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
                        goto failed_mount3a;
 
@@ -4033,23 +3670,47 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * The first inode we look at is the journal inode.  Don't try
         * root first: it may be modified in the journal!
         */
-       if (!test_opt(sb, NOLOAD) &&
-           EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+       if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
                if (ext4_load_journal(sb, es, journal_devnum))
                        goto failed_mount3a;
        } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
-             EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
+                  ext4_has_feature_journal_needs_recovery(sb)) {
                ext4_msg(sb, KERN_ERR, "required journal recovery "
                       "suppressed and not mounted read-only");
                goto failed_mount_wq;
        } else {
+               /* Nojournal mode, all journal mount options are illegal */
+               if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_checksum, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_async_commit, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "commit=%lu, fs mounted w/o journal",
+                                sbi->s_commit_interval / HZ);
+                       goto failed_mount_wq;
+               }
+               if (EXT4_MOUNT_DATA_FLAGS &
+                   (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "data=, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM;
+               clear_opt(sb, JOURNAL_CHECKSUM);
                clear_opt(sb, DATA_FLAGS);
                sbi->s_journal = NULL;
                needs_recovery = 0;
                goto no_journal;
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT) &&
+       if (ext4_has_feature_64bit(sb) &&
            !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
                                       JBD2_FEATURE_INCOMPAT_64BIT)) {
                ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature");
@@ -4101,18 +3762,16 @@ no_journal:
                }
        }
 
-       if ((DUMMY_ENCRYPTION_ENABLED(sbi) ||
-            EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) &&
+       if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
            (blocksize != PAGE_CACHE_SIZE)) {
                ext4_msg(sb, KERN_ERR,
                         "Unsupported blocksize for fs encryption");
                goto failed_mount_wq;
        }
 
-       if (DUMMY_ENCRYPTION_ENABLED(sbi) &&
-           !(sb->s_flags & MS_RDONLY) &&
-           !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
+       if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & MS_RDONLY) &&
+           !ext4_has_feature_encrypt(sb)) {
+               ext4_set_feature_encrypt(sb);
                ext4_commit_super(sb, 1);
        }
 
@@ -4171,8 +3830,7 @@ no_journal:
        if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
                sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
                                                     EXT4_GOOD_OLD_INODE_SIZE;
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+               if (ext4_has_feature_extra_isize(sb)) {
                        if (sbi->s_want_extra_isize <
                            le16_to_cpu(es->s_want_extra_isize))
                                sbi->s_want_extra_isize =
@@ -4192,12 +3850,7 @@ no_journal:
                         "available");
        }
 
-       err = ext4_reserve_clusters(sbi, ext4_calculate_resv_clusters(sb));
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for "
-                        "reserved pool", ext4_calculate_resv_clusters(sb));
-               goto failed_mount4a;
-       }
+       ext4_set_resv_clusters(sb);
 
        err = ext4_setup_system_zone(sb);
        if (err) {
@@ -4236,7 +3889,7 @@ no_journal:
                goto failed_mount6;
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+       if (ext4_has_feature_flex_bg(sb))
                if (!ext4_fill_flex_info(sb)) {
                        ext4_msg(sb, KERN_ERR,
                               "unable to initialize "
@@ -4248,17 +3901,13 @@ no_journal:
        if (err)
                goto failed_mount6;
 
-       sbi->s_kobj.kset = ext4_kset;
-       init_completion(&sbi->s_kobj_unregister);
-       err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL,
-                                  "%s", sb->s_id);
+       err = ext4_register_sysfs(sb);
        if (err)
                goto failed_mount7;
 
 #ifdef CONFIG_QUOTA
        /* Enable quota usage during mount. */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
-           !(sb->s_flags & MS_RDONLY)) {
+       if (ext4_has_feature_quota(sb) && !(sb->s_flags & MS_RDONLY)) {
                err = ext4_enable_quotas(sb);
                if (err)
                        goto failed_mount8;
@@ -4313,7 +3962,7 @@ cantfind_ext4:
 
 #ifdef CONFIG_QUOTA
 failed_mount8:
-       kobject_del(&sbi->s_kobj);
+       ext4_unregister_sysfs(sb);
 #endif
 failed_mount7:
        ext4_unregister_li_request(sb);
@@ -4353,10 +4002,6 @@ failed_mount2:
 failed_mount:
        if (sbi->s_chksum_driver)
                crypto_free_shash(sbi->s_chksum_driver);
-       if (sbi->s_proc) {
-               remove_proc_entry("options", sbi->s_proc);
-               remove_proc_entry(sb->s_id, ext4_proc_root);
-       }
 #ifdef CONFIG_QUOTA
        for (i = 0; i < EXT4_MAXQUOTAS; i++)
                kfree(sbi->s_qf_names[i]);
@@ -4403,7 +4048,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,
        struct inode *journal_inode;
        journal_t *journal;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        /* First, test for the existence of a valid inode on disk.  Bad
         * things happen if we iget() an unused inode, as the subsequent
@@ -4453,7 +4098,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        struct ext4_super_block *es;
        struct block_device *bdev;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        bdev = ext4_blkdev_get(j_dev, sb);
        if (bdev == NULL)
@@ -4545,7 +4190,7 @@ static int ext4_load_journal(struct super_block *sb,
        int err = 0;
        int really_read_only;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        if (journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
@@ -4562,7 +4207,7 @@ static int ext4_load_journal(struct super_block *sb,
         * crash?  For recovery, we need to check in advance whether we
         * can get read-write access to the device.
         */
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
+       if (ext4_has_feature_journal_needs_recovery(sb)) {
                if (sb->s_flags & MS_RDONLY) {
                        ext4_msg(sb, KERN_INFO, "INFO: recovery "
                                        "required on readonly filesystem");
@@ -4593,7 +4238,7 @@ static int ext4_load_journal(struct super_block *sb,
        if (!(journal->j_flags & JBD2_BARRIER))
                ext4_msg(sb, KERN_INFO, "barriers disabled");
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
+       if (!ext4_has_feature_journal_needs_recovery(sb))
                err = jbd2_journal_wipe(journal, !really_read_only);
        if (!err) {
                char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
@@ -4707,7 +4352,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
 {
        journal_t *journal = EXT4_SB(sb)->s_journal;
 
-       if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+       if (!ext4_has_feature_journal(sb)) {
                BUG_ON(journal != NULL);
                return;
        }
@@ -4715,9 +4360,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
        if (jbd2_journal_flush(journal) < 0)
                goto out;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
+       if (ext4_has_feature_journal_needs_recovery(sb) &&
            sb->s_flags & MS_RDONLY) {
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
                ext4_commit_super(sb, 1);
        }
 
@@ -4737,7 +4382,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
        int j_errno;
        const char *errstr;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        journal = EXT4_SB(sb)->s_journal;
 
@@ -4852,7 +4497,7 @@ static int ext4_freeze(struct super_block *sb)
                        goto out;
 
                /* Journal blocked and flushed, clear needs_recovery flag. */
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
        }
 
        error = ext4_commit_super(sb, 1);
@@ -4874,7 +4519,7 @@ static int ext4_unfreeze(struct super_block *sb)
 
        if (EXT4_SB(sb)->s_journal) {
                /* Reset the needs_recovery flag before the fs is unlocked. */
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_set_feature_journal_needs_recovery(sb);
        }
 
        ext4_commit_super(sb, 1);
@@ -5027,8 +4672,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                ext4_mark_recovery_complete(sb, es);
                } else {
                        /* Make sure we can mount this feature set readwrite */
-                       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_READONLY) ||
+                       if (ext4_has_feature_readonly(sb) ||
                            !ext4_feature_set_ok(sb, 0)) {
                                err = -EROFS;
                                goto restore_opts;
@@ -5044,9 +4688,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                if (!ext4_group_desc_csum_verify(sb, g, gdp)) {
                                        ext4_msg(sb, KERN_ERR,
               "ext4_remount: Checksum for group %u failed (%u!=%u)",
-               g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)),
+               g, le16_to_cpu(ext4_group_desc_csum(sb, g, gdp)),
                                               le16_to_cpu(gdp->bg_checksum));
-                                       err = -EINVAL;
+                                       err = -EFSBADCRC;
                                        goto restore_opts;
                                }
                        }
@@ -5076,8 +4720,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
-                       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                                    EXT4_FEATURE_INCOMPAT_MMP))
+                       if (ext4_has_feature_mmp(sb))
                                if (ext4_multi_mount_protect(sb,
                                                le64_to_cpu(es->s_mmp_block))) {
                                        err = -EROFS;
@@ -5110,8 +4753,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        if (enable_quota) {
                if (sb_any_quota_suspended(sb))
                        dquot_resume(sb, -1);
-               else if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+               else if (ext4_has_feature_quota(sb)) {
                        err = ext4_enable_quotas(sb);
                        if (err)
                                goto restore_opts;
@@ -5255,7 +4897,7 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        /* Are we journaling quotas? */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) ||
+       if (ext4_has_feature_quota(sb) ||
            sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
                dquot_mark_dquot_dirty(dquot);
                return ext4_write_dquot(dquot);
@@ -5343,7 +4985,7 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
                le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
        };
 
-       BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
+       BUG_ON(!ext4_has_feature_quota(sb));
 
        if (!qf_inums[type])
                return -EPERM;
@@ -5537,11 +5179,11 @@ static inline void unregister_as_ext2(void)
 
 static inline int ext2_feature_set_ok(struct super_block *sb)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))
+       if (ext4_has_unknown_ext2_incompat_features(sb))
                return 0;
        if (sb->s_flags & MS_RDONLY)
                return 1;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))
+       if (ext4_has_unknown_ext2_ro_compat_features(sb))
                return 0;
        return 1;
 }
@@ -5566,13 +5208,13 @@ static inline void unregister_as_ext3(void)
 
 static inline int ext3_feature_set_ok(struct super_block *sb)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))
+       if (ext4_has_unknown_ext3_incompat_features(sb))
                return 0;
-       if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
+       if (!ext4_has_feature_journal(sb))
                return 0;
        if (sb->s_flags & MS_RDONLY)
                return 1;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))
+       if (ext4_has_unknown_ext3_ro_compat_features(sb))
                return 0;
        return 1;
 }
@@ -5586,37 +5228,6 @@ static struct file_system_type ext4_fs_type = {
 };
 MODULE_ALIAS_FS("ext4");
 
-static int __init ext4_init_feat_adverts(void)
-{
-       struct ext4_features *ef;
-       int ret = -ENOMEM;
-
-       ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL);
-       if (!ef)
-               goto out;
-
-       ef->f_kobj.kset = ext4_kset;
-       init_completion(&ef->f_kobj_unregister);
-       ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL,
-                                  "features");
-       if (ret) {
-               kfree(ef);
-               goto out;
-       }
-
-       ext4_feat = ef;
-       ret = 0;
-out:
-       return ret;
-}
-
-static void ext4_exit_feat_adverts(void)
-{
-       kobject_put(&ext4_feat->f_kobj);
-       wait_for_completion(&ext4_feat->f_kobj_unregister);
-       kfree(ext4_feat);
-}
-
 /* Shared across all ext4 file systems */
 wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
 struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
@@ -5643,21 +5254,15 @@ static int __init ext4_init_fs(void)
 
        err = ext4_init_pageio();
        if (err)
-               goto out7;
+               goto out5;
 
        err = ext4_init_system_zone();
        if (err)
-               goto out6;
-       ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
-       if (!ext4_kset) {
-               err = -ENOMEM;
-               goto out5;
-       }
-       ext4_proc_root = proc_mkdir("fs/ext4", NULL);
+               goto out4;
 
-       err = ext4_init_feat_adverts();
+       err = ext4_init_sysfs();
        if (err)
-               goto out4;
+               goto out3;
 
        err = ext4_init_mballoc();
        if (err)
@@ -5682,16 +5287,12 @@ out1:
        ext4_mballoc_ready = 0;
        ext4_exit_mballoc();
 out2:
-       ext4_exit_feat_adverts();
-out4:
-       if (ext4_proc_root)
-               remove_proc_entry("fs/ext4", NULL);
-       kset_unregister(ext4_kset);
-out5:
+       ext4_exit_sysfs();
+out3:
        ext4_exit_system_zone();
-out6:
+out4:
        ext4_exit_pageio();
-out7:
+out5:
        ext4_exit_es();
 
        return err;
@@ -5706,9 +5307,7 @@ static void __exit ext4_exit_fs(void)
        unregister_filesystem(&ext4_fs_type);
        destroy_inodecache();
        ext4_exit_mballoc();
-       ext4_exit_feat_adverts();
-       remove_proc_entry("fs/ext4", NULL);
-       kset_unregister(ext4_kset);
+       ext4_exit_sysfs();
        ext4_exit_system_zone();
        ext4_exit_pageio();
        ext4_exit_es();
index c677f2c1044b6ab444d13a57a2582c88581d77de..abe2401ce405669f0d315319f5275a9fc321c697 100644 (file)
@@ -57,7 +57,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
             sizeof(struct ext4_encrypted_symlink_data) - 1) >
            max_size) {
                /* Symlink data on the disk is corrupted */
-               res = -EIO;
+               res = -EFSCORRUPTED;
                goto errout;
        }
        plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
new file mode 100644 (file)
index 0000000..1b57c72
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  linux/fs/ext4/sysfs.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Theodore Ts'o (tytso@mit.edu)
+ *
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include "ext4.h"
+#include "ext4_jbd2.h"
+
+typedef enum {
+       attr_noop,
+       attr_delayed_allocation_blocks,
+       attr_session_write_kbytes,
+       attr_lifetime_write_kbytes,
+       attr_reserved_clusters,
+       attr_inode_readahead,
+       attr_trigger_test_error,
+       attr_feature,
+       attr_pointer_ui,
+       attr_pointer_atomic,
+} attr_id_t;
+
+typedef enum {
+       ptr_explicit,
+       ptr_ext4_sb_info_offset,
+       ptr_ext4_super_block_offset,
+} attr_ptr_t;
+
+static const char *proc_dirname = "fs/ext4";
+static struct proc_dir_entry *ext4_proc_root;
+
+struct ext4_attr {
+       struct attribute attr;
+       short attr_id;
+       short attr_ptr;
+       union {
+               int offset;
+               void *explicit_ptr;
+       } u;
+};
+
+static ssize_t session_write_kbytes_show(struct ext4_attr *a,
+                                        struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       if (!sb->s_bdev->bd_part)
+               return snprintf(buf, PAGE_SIZE, "0\n");
+       return snprintf(buf, PAGE_SIZE, "%lu\n",
+                       (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                        sbi->s_sectors_written_start) >> 1);
+}
+
+static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi, char *buf)
+{
+       struct super_block *sb = sbi->s_buddy_cache->i_sb;
+
+       if (!sb->s_bdev->bd_part)
+               return snprintf(buf, PAGE_SIZE, "0\n");
+       return snprintf(buf, PAGE_SIZE, "%llu\n",
+                       (unsigned long long)(sbi->s_kbytes_written +
+                       ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
+                         EXT4_SB(sb)->s_sectors_written_start) >> 1)));
+}
+
+static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
+                                         struct ext4_sb_info *sbi,
+                                         const char *buf, size_t count)
+{
+       unsigned long t;
+       int ret;
+
+       ret = kstrtoul(skip_spaces(buf), 0, &t);
+       if (ret)
+               return ret;
+
+       if (t && (!is_power_of_2(t) || t > 0x40000000))
+               return -EINVAL;
+
+       sbi->s_inode_readahead_blks = t;
+       return count;
+}
+
+static ssize_t reserved_clusters_store(struct ext4_attr *a,
+                                  struct ext4_sb_info *sbi,
+                                  const char *buf, size_t count)
+{
+       unsigned long long val;
+       ext4_fsblk_t clusters = (ext4_blocks_count(sbi->s_es) >>
+                                sbi->s_cluster_bits);
+       int ret;
+
+       ret = kstrtoull(skip_spaces(buf), 0, &val);
+       if (!ret || val >= clusters)
+               return -EINVAL;
+
+       atomic64_set(&sbi->s_resv_clusters, val);
+       return count;
+}
+
+static ssize_t trigger_test_error(struct ext4_attr *a,
+                                 struct ext4_sb_info *sbi,
+                                 const char *buf, size_t count)
+{
+       int len = count;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (len && buf[len-1] == '\n')
+               len--;
+
+       if (len)
+               ext4_error(sbi->s_sb, "%.*s", len, buf);
+       return count;
+}
+
+#define EXT4_ATTR(_name,_mode,_id)                                     \
+static struct ext4_attr ext4_attr_##_name = {                          \
+       .attr = {.name = __stringify(_name), .mode = _mode },           \
+       .attr_id = attr_##_id,                                          \
+}
+
+#define EXT4_ATTR_FUNC(_name,_mode)  EXT4_ATTR(_name,_mode,_name)
+
+#define EXT4_ATTR_FEATURE(_name)   EXT4_ATTR(_name, 0444, feature)
+
+#define EXT4_ATTR_OFFSET(_name,_mode,_id,_struct,_elname)      \
+static struct ext4_attr ext4_attr_##_name = {                  \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .attr_id = attr_##_id,                                  \
+       .attr_ptr = ptr_##_struct##_offset,                     \
+       .u = {                                                  \
+               .offset = offsetof(struct _struct, _elname),\
+       },                                                      \
+}
+
+#define EXT4_RO_ATTR_ES_UI(_name,_elname)                              \
+       EXT4_ATTR_OFFSET(_name, 0444, pointer_ui, ext4_super_block, _elname)
+
+#define EXT4_RW_ATTR_SBI_UI(_name,_elname)     \
+       EXT4_ATTR_OFFSET(_name, 0644, pointer_ui, ext4_sb_info, _elname)
+
+#define EXT4_ATTR_PTR(_name,_mode,_id,_ptr) \
+static struct ext4_attr ext4_attr_##_name = {                  \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .attr_id = attr_##_id,                                  \
+       .attr_ptr = ptr_explicit,                               \
+       .u = {                                                  \
+               .explicit_ptr = _ptr,                           \
+       },                                                      \
+}
+
+#define ATTR_LIST(name) &ext4_attr_##name.attr
+
+EXT4_ATTR_FUNC(delayed_allocation_blocks, 0444);
+EXT4_ATTR_FUNC(session_write_kbytes, 0444);
+EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444);
+EXT4_ATTR_FUNC(reserved_clusters, 0644);
+
+EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead,
+                ext4_sb_info, s_inode_readahead_blks);
+EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
+EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
+EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
+EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
+EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
+EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
+EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb);
+EXT4_ATTR(trigger_fs_error, 0200, trigger_test_error);
+EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval);
+EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst);
+EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval);
+EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst);
+EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval);
+EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
+EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
+EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time);
+EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time);
+
+static unsigned int old_bump_val = 128;
+EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val);
+
+static struct attribute *ext4_attrs[] = {
+       ATTR_LIST(delayed_allocation_blocks),
+       ATTR_LIST(session_write_kbytes),
+       ATTR_LIST(lifetime_write_kbytes),
+       ATTR_LIST(reserved_clusters),
+       ATTR_LIST(inode_readahead_blks),
+       ATTR_LIST(inode_goal),
+       ATTR_LIST(mb_stats),
+       ATTR_LIST(mb_max_to_scan),
+       ATTR_LIST(mb_min_to_scan),
+       ATTR_LIST(mb_order2_req),
+       ATTR_LIST(mb_stream_req),
+       ATTR_LIST(mb_group_prealloc),
+       ATTR_LIST(max_writeback_mb_bump),
+       ATTR_LIST(extent_max_zeroout_kb),
+       ATTR_LIST(trigger_fs_error),
+       ATTR_LIST(err_ratelimit_interval_ms),
+       ATTR_LIST(err_ratelimit_burst),
+       ATTR_LIST(warning_ratelimit_interval_ms),
+       ATTR_LIST(warning_ratelimit_burst),
+       ATTR_LIST(msg_ratelimit_interval_ms),
+       ATTR_LIST(msg_ratelimit_burst),
+       ATTR_LIST(errors_count),
+       ATTR_LIST(first_error_time),
+       ATTR_LIST(last_error_time),
+       NULL,
+};
+
+/* Features this copy of ext4 supports */
+EXT4_ATTR_FEATURE(lazy_itable_init);
+EXT4_ATTR_FEATURE(batched_discard);
+EXT4_ATTR_FEATURE(meta_bg_resize);
+EXT4_ATTR_FEATURE(encryption);
+EXT4_ATTR_FEATURE(metadata_csum_seed);
+
+static struct attribute *ext4_feat_attrs[] = {
+       ATTR_LIST(lazy_itable_init),
+       ATTR_LIST(batched_discard),
+       ATTR_LIST(meta_bg_resize),
+       ATTR_LIST(encryption),
+       ATTR_LIST(metadata_csum_seed),
+       NULL,
+};
+
+static void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi)
+{
+       switch (a->attr_ptr) {
+       case ptr_explicit:
+               return a->u.explicit_ptr;
+       case ptr_ext4_sb_info_offset:
+               return (void *) (((char *) sbi) + a->u.offset);
+       case ptr_ext4_super_block_offset:
+               return (void *) (((char *) sbi->s_es) + a->u.offset);
+       }
+       return NULL;
+}
+
+static ssize_t ext4_attr_show(struct kobject *kobj,
+                             struct attribute *attr, char *buf)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+       void *ptr = calc_ptr(a, sbi);
+
+       switch (a->attr_id) {
+       case attr_delayed_allocation_blocks:
+               return snprintf(buf, PAGE_SIZE, "%llu\n",
+                               (s64) EXT4_C2B(sbi,
+                      percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
+       case attr_session_write_kbytes:
+               return session_write_kbytes_show(a, sbi, buf);
+       case attr_lifetime_write_kbytes:
+               return lifetime_write_kbytes_show(a, sbi, buf);
+       case attr_reserved_clusters:
+               return snprintf(buf, PAGE_SIZE, "%llu\n",
+                               (unsigned long long)
+                               atomic64_read(&sbi->s_resv_clusters));
+       case attr_inode_readahead:
+       case attr_pointer_ui:
+               if (!ptr)
+                       return 0;
+               return snprintf(buf, PAGE_SIZE, "%u\n",
+                               *((unsigned int *) ptr));
+       case attr_pointer_atomic:
+               if (!ptr)
+                       return 0;
+               return snprintf(buf, PAGE_SIZE, "%d\n",
+                               atomic_read((atomic_t *) ptr));
+       case attr_feature:
+               return snprintf(buf, PAGE_SIZE, "supported\n");
+       }
+
+       return 0;
+}
+
+static ssize_t ext4_attr_store(struct kobject *kobj,
+                              struct attribute *attr,
+                              const char *buf, size_t len)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       struct ext4_attr *a = container_of(attr, struct ext4_attr, attr);
+       void *ptr = calc_ptr(a, sbi);
+       unsigned long t;
+       int ret;
+
+       switch (a->attr_id) {
+       case attr_reserved_clusters:
+               return reserved_clusters_store(a, sbi, buf, len);
+       case attr_pointer_ui:
+               if (!ptr)
+                       return 0;
+               ret = kstrtoul(skip_spaces(buf), 0, &t);
+               if (ret)
+                       return ret;
+               *((unsigned int *) ptr) = t;
+               return len;
+       case attr_inode_readahead:
+               return inode_readahead_blks_store(a, sbi, buf, len);
+       case attr_trigger_test_error:
+               return trigger_test_error(a, sbi, buf, len);
+       }
+       return 0;
+}
+
+static void ext4_sb_release(struct kobject *kobj)
+{
+       struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info,
+                                               s_kobj);
+       complete(&sbi->s_kobj_unregister);
+}
+
+static const struct sysfs_ops ext4_attr_ops = {
+       .show   = ext4_attr_show,
+       .store  = ext4_attr_store,
+};
+
+static struct kobj_type ext4_sb_ktype = {
+       .default_attrs  = ext4_attrs,
+       .sysfs_ops      = &ext4_attr_ops,
+       .release        = ext4_sb_release,
+};
+
+static struct kobj_type ext4_ktype = {
+       .sysfs_ops      = &ext4_attr_ops,
+};
+
+static struct kset ext4_kset = {
+       .kobj   = {.ktype = &ext4_ktype},
+};
+
+static struct kobj_type ext4_feat_ktype = {
+       .default_attrs  = ext4_feat_attrs,
+       .sysfs_ops      = &ext4_attr_ops,
+};
+
+static struct kobject ext4_feat = {
+       .kset   = &ext4_kset,
+};
+
+#define PROC_FILE_SHOW_DEFN(name) \
+static int name##_open(struct inode *inode, struct file *file) \
+{ \
+       return single_open(file, ext4_seq_##name##_show, PDE_DATA(inode)); \
+} \
+\
+const struct file_operations ext4_seq_##name##_fops = { \
+       .owner          = THIS_MODULE, \
+       .open           = name##_open, \
+       .read           = seq_read, \
+       .llseek         = seq_lseek, \
+       .release        = single_release, \
+}
+
+#define PROC_FILE_LIST(name) \
+       { __stringify(name), &ext4_seq_##name##_fops }
+
+PROC_FILE_SHOW_DEFN(es_shrinker_info);
+PROC_FILE_SHOW_DEFN(options);
+
+static struct ext4_proc_files {
+       const char *name;
+       const struct file_operations *fops;
+} proc_files[] = {
+       PROC_FILE_LIST(options),
+       PROC_FILE_LIST(es_shrinker_info),
+       PROC_FILE_LIST(mb_groups),
+       { NULL, NULL },
+};
+
+int ext4_register_sysfs(struct super_block *sb)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_proc_files *p;
+       int err;
+
+       sbi->s_kobj.kset = &ext4_kset;
+       init_completion(&sbi->s_kobj_unregister);
+       err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, NULL,
+                                  "%s", sb->s_id);
+       if (err)
+               return err;
+
+       if (ext4_proc_root)
+               sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
+
+       if (sbi->s_proc) {
+               for (p = proc_files; p->name; p++)
+                       proc_create_data(p->name, S_IRUGO, sbi->s_proc,
+                                        p->fops, sb);
+       }
+       return 0;
+}
+
+void ext4_unregister_sysfs(struct super_block *sb)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_proc_files *p;
+
+       if (sbi->s_proc) {
+               for (p = proc_files; p->name; p++)
+                       remove_proc_entry(p->name, sbi->s_proc);
+               remove_proc_entry(sb->s_id, ext4_proc_root);
+       }
+       kobject_del(&sbi->s_kobj);
+}
+
+int __init ext4_init_sysfs(void)
+{
+       int ret;
+
+       kobject_set_name(&ext4_kset.kobj, "ext4");
+       ext4_kset.kobj.parent = fs_kobj;
+       ret = kset_register(&ext4_kset);
+       if (ret)
+               return ret;
+
+       ret = kobject_init_and_add(&ext4_feat, &ext4_feat_ktype,
+                                  NULL, "features");
+       if (ret)
+               kset_unregister(&ext4_kset);
+       else
+               ext4_proc_root = proc_mkdir(proc_dirname, NULL);
+       return ret;
+}
+
+void ext4_exit_sysfs(void)
+{
+       kobject_put(&ext4_feat);
+       kset_unregister(&ext4_kset);
+       remove_proc_entry(proc_dirname, NULL);
+       ext4_proc_root = NULL;
+}
+
index 16e28c08d1e8cf54eb0c05d15611a6416185b119..984448c6f5f0af1d429a982cce28f7ab26b3b093 100644 (file)
@@ -195,7 +195,7 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
        while (!IS_LAST_ENTRY(e)) {
                struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
                if ((void *)next >= end)
-                       return -EIO;
+                       return -EFSCORRUPTED;
                e = next;
        }
 
@@ -205,7 +205,7 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
                     (void *)e + sizeof(__u32) ||
                     value_start + le16_to_cpu(entry->e_value_offs) +
                    le32_to_cpu(entry->e_value_size) > end))
-                       return -EIO;
+                       return -EFSCORRUPTED;
                entry = EXT4_XATTR_NEXT(entry);
        }
 
@@ -222,9 +222,9 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
 
        if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
            BHDR(bh)->h_blocks != cpu_to_le32(1))
-               return -EIO;
+               return -EFSCORRUPTED;
        if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
-               return -EIO;
+               return -EFSBADCRC;
        error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
                                       bh->b_data);
        if (!error)
@@ -239,7 +239,7 @@ ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
 
        if (entry->e_value_block != 0 || value_size > size ||
            le16_to_cpu(entry->e_value_offs) + value_size > size)
-               return -EIO;
+               return -EFSCORRUPTED;
        return 0;
 }
 
@@ -266,7 +266,7 @@ ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
        }
        *pentry = entry;
        if (!cmp && ext4_xattr_check_entry(entry, size))
-                       return -EIO;
+               return -EFSCORRUPTED;
        return cmp ? -ENODATA : 0;
 }
 
@@ -297,13 +297,13 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
 bad_block:
                EXT4_ERROR_INODE(inode, "bad block %llu",
                                 EXT4_I(inode)->i_file_acl);
-               error = -EIO;
+               error = -EFSCORRUPTED;
                goto cleanup;
        }
        ext4_xattr_cache_insert(ext4_mb_cache, bh);
        entry = BFIRST(bh);
        error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
-       if (error == -EIO)
+       if (error == -EFSCORRUPTED)
                goto bad_block;
        if (error)
                goto cleanup;
@@ -445,7 +445,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        if (ext4_xattr_check_block(inode, bh)) {
                EXT4_ERROR_INODE(inode, "bad block %llu",
                                 EXT4_I(inode)->i_file_acl);
-               error = -EIO;
+               error = -EFSCORRUPTED;
                goto cleanup;
        }
        ext4_xattr_cache_insert(ext4_mb_cache, bh);
@@ -525,12 +525,12 @@ errout:
 static void ext4_xattr_update_super_block(handle_t *handle,
                                          struct super_block *sb)
 {
-       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR))
+       if (ext4_has_feature_xattr(sb))
                return;
 
        BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
        if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
-               EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
+               ext4_set_feature_xattr(sb);
                ext4_handle_dirty_super(handle, sb);
        }
 }
@@ -751,7 +751,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
                if (ext4_xattr_check_block(inode, bs->bh)) {
                        EXT4_ERROR_INODE(inode, "bad block %llu",
                                         EXT4_I(inode)->i_file_acl);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto cleanup;
                }
                /* Find the named attribute. */
@@ -811,7 +811,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                                        bs->bh);
                        }
                        unlock_buffer(bs->bh);
-                       if (error == -EIO)
+                       if (error == -EFSCORRUPTED)
                                goto bad_block;
                        if (!error)
                                error = ext4_handle_dirty_xattr_block(handle,
@@ -855,7 +855,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
        }
 
        error = ext4_xattr_set_entry(i, s);
-       if (error == -EIO)
+       if (error == -EFSCORRUPTED)
                goto bad_block;
        if (error)
                goto cleanup;
@@ -1314,7 +1314,7 @@ retry:
                if (ext4_xattr_check_block(inode, bh)) {
                        EXT4_ERROR_INODE(inode, "bad block %llu",
                                         EXT4_I(inode)->i_file_acl);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto cleanup;
                }
                base = BHDR(bh);
@@ -1579,7 +1579,7 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1,
                    memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
                        return 1;
                if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
-                       return -EIO;
+                       return -EFSCORRUPTED;
                if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
                           (char *)header2 + le16_to_cpu(entry2->e_value_offs),
                           le32_to_cpu(entry1->e_value_size)))
index 8c44654ce2748ae1acf03442c6cc9b31b48b440b..684996c8a3a4a2df646dc44c4ee4e90904470989 100644 (file)
@@ -427,7 +427,6 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
        struct journal_head *last_jh;
        struct journal_head *next_jh = jh;
        int ret;
-       int freed = 0;
 
        if (!jh)
                return 0;
@@ -441,10 +440,9 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
                else
                        ret = __jbd2_journal_remove_checkpoint(jh) + 1;
                if (!ret)
-                       return freed;
+                       return 0;
                if (ret == 2)
                        return 1;
-               freed = 1;
                /*
                 * This function only frees up some memory
                 * if possible so we dont have an obligation
@@ -452,10 +450,10 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
                 * requested:
                 */
                if (need_resched())
-                       return freed;
+                       return 0;
        } while (jh != last_jh);
 
-       return freed;
+       return 0;
 }
 
 /*
index 362e5f614450e53e2b407b988b4b70254a193ca2..36345fefa3ffee1f66e56c908cca50b282abeba5 100644 (file)
@@ -142,8 +142,7 @@ static int journal_submit_commit_record(journal_t *journal,
        tmp->h_commit_sec = cpu_to_be64(now.tv_sec);
        tmp->h_commit_nsec = cpu_to_be32(now.tv_nsec);
 
-       if (JBD2_HAS_COMPAT_FEATURE(journal,
-                                   JBD2_FEATURE_COMPAT_CHECKSUM)) {
+       if (jbd2_has_feature_checksum(journal)) {
                tmp->h_chksum_type      = JBD2_CRC32_CHKSUM;
                tmp->h_chksum_size      = JBD2_CRC32_CHKSUM_SIZE;
                tmp->h_chksum[0]        = cpu_to_be32(crc32_sum);
@@ -157,8 +156,7 @@ static int journal_submit_commit_record(journal_t *journal,
        bh->b_end_io = journal_end_buffer_io_sync;
 
        if (journal->j_flags & JBD2_BARRIER &&
-           !JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT))
+           !jbd2_has_feature_async_commit(journal))
                ret = submit_bh(WRITE_SYNC | WRITE_FLUSH_FUA, bh);
        else
                ret = submit_bh(WRITE_SYNC, bh);
@@ -317,7 +315,7 @@ static void write_tag_block(journal_t *j, journal_block_tag_t *tag,
                                   unsigned long long block)
 {
        tag->t_blocknr = cpu_to_be32(block & (u32)~0);
-       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(j))
                tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
 }
 
@@ -356,7 +354,7 @@ static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
                             bh->b_size);
        kunmap_atomic(addr);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+       if (jbd2_has_feature_csum3(j))
                tag3->t_checksum = cpu_to_be32(csum32);
        else
                tag->t_checksum = cpu_to_be16(csum32);
@@ -730,8 +728,7 @@ start_journal_io:
                                /*
                                 * Compute checksum.
                                 */
-                               if (JBD2_HAS_COMPAT_FEATURE(journal,
-                                       JBD2_FEATURE_COMPAT_CHECKSUM)) {
+                               if (jbd2_has_feature_checksum(journal)) {
                                        crc32_sum =
                                            jbd2_checksum_data(crc32_sum, bh);
                                }
@@ -797,8 +794,7 @@ start_journal_io:
                blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL);
 
        /* Done it all: now write the commit record asynchronously. */
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                     JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+       if (jbd2_has_feature_async_commit(journal)) {
                err = journal_submit_commit_record(journal, commit_transaction,
                                                 &cbh, crc32_sum);
                if (err)
@@ -889,8 +885,7 @@ start_journal_io:
        commit_transaction->t_state = T_COMMIT_JFLUSH;
        write_unlock(&journal->j_state_lock);
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+       if (!jbd2_has_feature_async_commit(journal)) {
                err = journal_submit_commit_record(journal, commit_transaction,
                                                &cbh, crc32_sum);
                if (err)
@@ -898,8 +893,7 @@ start_journal_io:
        }
        if (cbh)
                err = journal_wait_on_commit_record(journal, cbh);
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                     JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) &&
+       if (jbd2_has_feature_async_commit(journal) &&
            journal->j_flags & JBD2_BARRIER) {
                blkdev_issue_flush(journal->j_dev, GFP_NOFS, NULL);
        }
index 8270fe9e3641eb52521ef288ee46047559835bfb..81e622681c82273aa050eb85cdb057b1fea0e79e 100644 (file)
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(__jbd2_debug);
 /* Checksumming functions */
 static int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb)
 {
-       if (!jbd2_journal_has_csum_v2or3(j))
+       if (!jbd2_journal_has_csum_v2or3_feature(j))
                return 1;
 
        return sb->s_checksum_type == JBD2_CRC32C_CHKSUM;
@@ -1523,16 +1523,16 @@ static int journal_get_superblock(journal_t *journal)
                goto out;
        }
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) &&
-           JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) {
+       if (jbd2_has_feature_csum2(journal) &&
+           jbd2_has_feature_csum3(journal)) {
                /* Can't have checksum v2 and v3 at the same time! */
                printk(KERN_ERR "JBD2: Can't enable checksumming v2 and v3 "
                       "at the same time!\n");
                goto out;
        }
 
-       if (jbd2_journal_has_csum_v2or3(journal) &&
-           JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM)) {
+       if (jbd2_journal_has_csum_v2or3_feature(journal) &&
+           jbd2_has_feature_checksum(journal)) {
                /* Can't have checksum v1 and v2 on at the same time! */
                printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2/3 "
                       "at the same time!\n");
@@ -1545,7 +1545,7 @@ static int journal_get_superblock(journal_t *journal)
        }
 
        /* Load the checksum driver */
-       if (jbd2_journal_has_csum_v2or3(journal)) {
+       if (jbd2_journal_has_csum_v2or3_feature(journal)) {
                journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
                if (IS_ERR(journal->j_chksum_driver)) {
                        printk(KERN_ERR "JBD2: Cannot load crc32c driver.\n");
@@ -1558,6 +1558,7 @@ static int journal_get_superblock(journal_t *journal)
        /* Check superblock checksum */
        if (!jbd2_superblock_csum_verify(journal, sb)) {
                printk(KERN_ERR "JBD2: journal checksum error\n");
+               err = -EFSBADCRC;
                goto out;
        }
 
@@ -1649,7 +1650,7 @@ int jbd2_journal_load(journal_t *journal)
                printk(KERN_ERR "JBD2: journal transaction %u on %s "
                       "is corrupt.\n", journal->j_failed_commit,
                       journal->j_devname);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /* OK, we've finished with the dynamic journal bits:
@@ -2071,8 +2072,12 @@ static void __journal_abort_soft (journal_t *journal, int errno)
 
        __jbd2_journal_abort_hard(journal);
 
-       if (errno)
+       if (errno) {
                jbd2_journal_update_sb_errno(journal);
+               write_lock(&journal->j_state_lock);
+               journal->j_flags |= JBD2_REC_ERR;
+               write_unlock(&journal->j_state_lock);
+       }
 }
 
 /**
@@ -2197,15 +2202,15 @@ size_t journal_tag_bytes(journal_t *journal)
 {
        size_t sz;
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+       if (jbd2_has_feature_csum3(journal))
                return sizeof(journal_block_tag3_t);
 
        sz = sizeof(journal_block_tag_t);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (jbd2_has_feature_csum2(journal))
                sz += sizeof(__u16);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(journal))
                return sz;
        else
                return sz - sizeof(__u32);
index a9079d035ae59d9a6983bcaa79625ce5f0e5c343..7f277e49fe8841edcf87c45a652b98c316c8b35e 100644 (file)
@@ -140,7 +140,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
 
        if (offset >= journal->j_maxlen) {
                printk(KERN_ERR "JBD2: corrupted journal superblock\n");
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        err = jbd2_journal_bmap(journal, offset, &blocknr);
@@ -342,7 +342,7 @@ static inline unsigned long long read_tag_block(journal_t *journal,
                                                journal_block_tag_t *tag)
 {
        unsigned long long block = be32_to_cpu(tag->t_blocknr);
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(journal))
                block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;
        return block;
 }
@@ -411,7 +411,7 @@ static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
        csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
        csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+       if (jbd2_has_feature_csum3(j))
                return tag3->t_checksum == cpu_to_be32(csum32);
        else
                return tag->t_checksum == cpu_to_be16(csum32);
@@ -527,7 +527,7 @@ static int do_one_pass(journal_t *journal,
                                printk(KERN_ERR "JBD2: Invalid checksum "
                                       "recovering block %lu in log\n",
                                       next_log_block);
-                               err = -EIO;
+                               err = -EFSBADCRC;
                                brelse(bh);
                                goto failed;
                        }
@@ -538,8 +538,7 @@ static int do_one_pass(journal_t *journal,
                         * just skip over the blocks it describes. */
                        if (pass != PASS_REPLAY) {
                                if (pass == PASS_SCAN &&
-                                   JBD2_HAS_COMPAT_FEATURE(journal,
-                                           JBD2_FEATURE_COMPAT_CHECKSUM) &&
+                                   jbd2_has_feature_checksum(journal) &&
                                    !info->end_transaction) {
                                        if (calc_chksums(journal, bh,
                                                        &next_log_block,
@@ -602,7 +601,7 @@ static int do_one_pass(journal_t *journal,
                                                journal, tag, obh->b_data,
                                                be32_to_cpu(tmp->h_sequence))) {
                                                brelse(obh);
-                                               success = -EIO;
+                                               success = -EFSBADCRC;
                                                printk(KERN_ERR "JBD2: Invalid "
                                                       "checksum recovering "
                                                       "block %llu in log\n",
@@ -694,8 +693,7 @@ static int do_one_pass(journal_t *journal,
                         * much to do other than move on to the next sequence
                         * number. */
                        if (pass == PASS_SCAN &&
-                           JBD2_HAS_COMPAT_FEATURE(journal,
-                                   JBD2_FEATURE_COMPAT_CHECKSUM)) {
+                           jbd2_has_feature_checksum(journal)) {
                                int chksum_err, chksum_seen;
                                struct commit_header *cbh =
                                        (struct commit_header *)bh->b_data;
@@ -735,8 +733,7 @@ static int do_one_pass(journal_t *journal,
                                if (chksum_err) {
                                        info->end_transaction = next_commit_ID;
 
-                                       if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                          JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)){
+                                       if (!jbd2_has_feature_async_commit(journal)) {
                                                journal->j_failed_commit =
                                                        next_commit_ID;
                                                brelse(bh);
@@ -750,8 +747,7 @@ static int do_one_pass(journal_t *journal,
                                                           bh->b_data)) {
                                info->end_transaction = next_commit_ID;
 
-                               if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                    JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+                               if (!jbd2_has_feature_async_commit(journal)) {
                                        journal->j_failed_commit =
                                                next_commit_ID;
                                        brelse(bh);
@@ -851,7 +847,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
        rcount = be32_to_cpu(header->r_count);
 
        if (!jbd2_revoke_block_csum_verify(journal, header))
-               return -EINVAL;
+               return -EFSBADCRC;
 
        if (jbd2_journal_has_csum_v2or3(journal))
                csum_size = sizeof(struct jbd2_journal_revoke_tail);
@@ -859,7 +855,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
                return -EINVAL;
        max = rcount;
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(journal))
                record_len = 8;
 
        while (offset + record_len <= max) {
index 0abf2e7f725beb70135a4b65f90f6ada6f14134d..705ae577882b104d438957e0760a4608d93ceeb2 100644 (file)
@@ -589,7 +589,7 @@ static void write_one_revoke_record(journal_t *journal,
        if (jbd2_journal_has_csum_v2or3(journal))
                csum_size = sizeof(struct jbd2_journal_revoke_tail);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(journal))
                sz = 8;
        else
                sz = 4;
@@ -619,7 +619,7 @@ static void write_one_revoke_record(journal_t *journal,
                *descriptorp = descriptor;
        }
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+       if (jbd2_has_feature_64bit(journal))
                * ((__be64 *)(&descriptor->b_data[offset])) =
                        cpu_to_be64(record->blocknr);
        else
index 81180022923fbd8ccd499d0b74af05b59695c302..d211b8e18566719c873838268217b143966e5965 100644 (file)
@@ -621,9 +621,6 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode
        uint32_t alloclen;
        int ret;
 
-       if (!new_valid_dev(rdev))
-               return -EINVAL;
-
        ri = jffs2_alloc_raw_inode();
        if (!ri)
                return -ENOMEM;
index b8fd651307a42e2fce3d15dfcc1976e2526932ab..ce11897932889dfcd707140e331e11615e0ebaed 100644 (file)
@@ -97,25 +97,16 @@ int __init jffs2_create_slab_caches(void)
 
 void jffs2_destroy_slab_caches(void)
 {
-       if(full_dnode_slab)
-               kmem_cache_destroy(full_dnode_slab);
-       if(raw_dirent_slab)
-               kmem_cache_destroy(raw_dirent_slab);
-       if(raw_inode_slab)
-               kmem_cache_destroy(raw_inode_slab);
-       if(tmp_dnode_info_slab)
-               kmem_cache_destroy(tmp_dnode_info_slab);
-       if(raw_node_ref_slab)
-               kmem_cache_destroy(raw_node_ref_slab);
-       if(node_frag_slab)
-               kmem_cache_destroy(node_frag_slab);
-       if(inode_cache_slab)
-               kmem_cache_destroy(inode_cache_slab);
+       kmem_cache_destroy(full_dnode_slab);
+       kmem_cache_destroy(raw_dirent_slab);
+       kmem_cache_destroy(raw_inode_slab);
+       kmem_cache_destroy(tmp_dnode_info_slab);
+       kmem_cache_destroy(raw_node_ref_slab);
+       kmem_cache_destroy(node_frag_slab);
+       kmem_cache_destroy(inode_cache_slab);
 #ifdef CONFIG_JFFS2_FS_XATTR
-       if (xattr_datum_cache)
-               kmem_cache_destroy(xattr_datum_cache);
-       if (xattr_ref_cache)
-               kmem_cache_destroy(xattr_ref_cache);
+       kmem_cache_destroy(xattr_datum_cache);
+       kmem_cache_destroy(xattr_ref_cache);
 #endif
 }
 
index 28e0aab42bc34f6a26f67b82bc3f8c94a9bf4232..bfebbf13698c0e0d255e20f5ebf26de7fd6b5845 100644 (file)
@@ -660,8 +660,12 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
 
                err = jffs2_flash_read(c, (ref_offset(ref)) + read,
                                rd->nsize - already, &read, &fd->name[already]);
-               if (unlikely(read != rd->nsize - already) && likely(!err))
+               if (unlikely(read != rd->nsize - already) && likely(!err)) {
+                       jffs2_free_full_dirent(fd);
+                       JFFS2_ERROR("short read: wanted %d bytes, got %zd\n",
+                                   rd->nsize - already, read);
                        return -EIO;
+               }
 
                if (unlikely(err)) {
                        JFFS2_ERROR("read remainder of name: error %d\n", err);
index 955da626ba6b7f74d02a7d7dd5badb5e2a031430..f3a4857ff0718794b967836e796b8f9c9e345ae7 100644 (file)
@@ -1274,7 +1274,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
 #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
        c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf_verify) {
-               kfree(c->oobbuf);
                kfree(c->wbuf);
                return -ENOMEM;
        }
index 3c18970a8899464fc1eaaf3d02585acd2a2a6330..d84d7c7515fc44415f11488f192e52ef3c9c9990 100644 (file)
@@ -1966,7 +1966,7 @@ OK:
                if (err) {
                        const char *s = get_link(nd);
 
-                       if (unlikely(IS_ERR(s)))
+                       if (IS_ERR(s))
                                return PTR_ERR(s);
                        err = 0;
                        if (unlikely(!s)) {
@@ -3380,7 +3380,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
                return ERR_PTR(-ELOOP);
 
        filename = getname_kernel(name);
-       if (unlikely(IS_ERR(filename)))
+       if (IS_ERR(filename))
                return ERR_CAST(filename);
 
        set_nameidata(&nd, -1, filename);
index 93575e91a7aa7b2993afb16b781c657fa2d6a7af..356816e7bc90d2d2de4a4fc0e25b10ad42b839dc 100644 (file)
@@ -597,7 +597,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx,
        qname.name = __name;
 
        newdent = d_hash_and_lookup(dentry, &qname);
-       if (unlikely(IS_ERR(newdent)))
+       if (IS_ERR(newdent))
                goto end_advance;
        if (!newdent) {
                newdent = d_alloc(dentry, &qname);
index 5aaed363556a66e7bd5bb43d4619d037108f5421..5c0c6b58157f906d6c35ce737a6d4a5623027bf1 100644 (file)
@@ -124,7 +124,7 @@ objio_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
 
 retry_lookup:
        od = osduld_info_lookup(&odi);
-       if (unlikely(IS_ERR(od))) {
+       if (IS_ERR(od)) {
                err = PTR_ERR(od);
                dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
                if (err == -ENODEV && retry_flag) {
index fdda62e6115e1c4584cc88d360c27de7a26e1793..fe5b6e6c46719a79de1d808de782ccfd20bf67a8 100644 (file)
@@ -948,7 +948,7 @@ static struct ctl_dir *get_subdir(struct ctl_dir *dir,
 found:
        subdir->header.nreg++;
 failed:
-       if (unlikely(IS_ERR(subdir))) {
+       if (IS_ERR(subdir)) {
                pr_err("sysctl could not get directory: ");
                sysctl_print_dir(dir);
                pr_cont("/%*.*s %ld\n",
index cbc8d5d2755a691a560c46f7105e85ca6220d835..c66f2423e1f5c511b0202cfdab46a5e2be53d7f8 100644 (file)
@@ -340,8 +340,12 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
                dput(dentry);
                dentry = ERR_PTR(-EEXIST);
        }
-       if (IS_ERR(dentry))
+
+       if (IS_ERR(dentry)) {
                mutex_unlock(&parent->d_inode->i_mutex);
+               simple_release_fs(&tracefs_mount, &tracefs_mount_count);
+       }
+
        return dentry;
 }
 
diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h
deleted file mode 100644 (file)
index 97520d2..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Count leading and trailing zeros functions
- *
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
-#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
-
-#include <asm/bitops.h>
-
-/**
- * count_leading_zeros - Count the number of zeros from the MSB back
- * @x: The value
- *
- * Count the number of leading zeros from the MSB going towards the LSB in @x.
- *
- * If the MSB of @x is set, the result is 0.
- * If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
- * If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
- */
-static inline int count_leading_zeros(unsigned long x)
-{
-       if (sizeof(x) == 4)
-               return BITS_PER_LONG - fls(x);
-       else
-               return BITS_PER_LONG - fls64(x);
-}
-
-#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
-
-/**
- * count_trailing_zeros - Count the number of zeros from the LSB forwards
- * @x: The value
- *
- * Count the number of trailing zeros from the LSB going towards the MSB in @x.
- *
- * If the LSB of @x is set, the result is 0.
- * If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
- * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
- */
-static inline int count_trailing_zeros(unsigned long x)
-{
-#define COUNT_TRAILING_ZEROS_0 (-1)
-
-       if (sizeof(x) == 4)
-               return ffs(x);
-       else
-               return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
-}
-
-#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
index 3766ab34aa45afae86287a7c213c3311c88b4be2..e5f9080e8e8600c359ffaab6ba2adad660402c52 100644 (file)
@@ -79,8 +79,10 @@ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
        }
 }
 
-#define xchg(ptr, x) \
-       ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+#define xchg(ptr, x) ({                                                        \
+       ((__typeof__(*(ptr)))                                           \
+               __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));     \
+})
 
 #endif /* xchg */
 
@@ -90,9 +92,10 @@ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 #include <asm-generic/cmpxchg-local.h>
 
 #ifndef cmpxchg_local
-#define cmpxchg_local(ptr, o, n)                                              \
+#define cmpxchg_local(ptr, o, n) ({                                           \
        ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-                       (unsigned long)(n), sizeof(*(ptr))))
+                       (unsigned long)(n), sizeof(*(ptr))));                  \
+})
 #endif
 
 #ifndef cmpxchg64_local
index 2e29d13fc1541b45d9b73b6282e2163f00815bb4..32b73abce1b0ca52bcd44ef93d1acfcf0ec551b0 100644 (file)
@@ -1,32 +1,2 @@
-#ifndef _ASM_IO_64_NONATOMIC_HI_LO_H_
-#define _ASM_IO_64_NONATOMIC_HI_LO_H_
-
-#include <linux/io.h>
-#include <asm-generic/int-ll64.h>
-
-static inline __u64 hi_lo_readq(const volatile void __iomem *addr)
-{
-       const volatile u32 __iomem *p = addr;
-       u32 low, high;
-
-       high = readl(p + 1);
-       low = readl(p);
-
-       return low + ((u64)high << 32);
-}
-
-static inline void hi_lo_writeq(__u64 val, volatile void __iomem *addr)
-{
-       writel(val >> 32, addr + 4);
-       writel(val, addr);
-}
-
-#ifndef readq
-#define readq hi_lo_readq
-#endif
-
-#ifndef writeq
-#define writeq hi_lo_writeq
-#endif
-
-#endif /* _ASM_IO_64_NONATOMIC_HI_LO_H_ */
+/* XXX: delete asm-generic/io-64-nonatomic-hi-lo.h after converting new users */
+#include <linux/io-64-nonatomic-hi-lo.h>
index 0efacff0a1ce4db42d31038cd83163218239fcfe..55a627c37721b9c0017d1bc848911450d7e3a196 100644 (file)
@@ -1,32 +1,2 @@
-#ifndef _ASM_IO_64_NONATOMIC_LO_HI_H_
-#define _ASM_IO_64_NONATOMIC_LO_HI_H_
-
-#include <linux/io.h>
-#include <asm-generic/int-ll64.h>
-
-static inline __u64 lo_hi_readq(const volatile void __iomem *addr)
-{
-       const volatile u32 __iomem *p = addr;
-       u32 low, high;
-
-       low = readl(p);
-       high = readl(p + 1);
-
-       return low + ((u64)high << 32);
-}
-
-static inline void lo_hi_writeq(__u64 val, volatile void __iomem *addr)
-{
-       writel(val, addr);
-       writel(val >> 32, addr + 4);
-}
-
-#ifndef readq
-#define readq lo_hi_readq
-#endif
-
-#ifndef writeq
-#define writeq lo_hi_writeq
-#endif
-
-#endif /* _ASM_IO_64_NONATOMIC_LO_HI_H_ */
+/* XXX: delete asm-generic/io-64-nonatomic-lo-hi.h after converting new users */
+#include <linux/io-64-nonatomic-lo-hi.h>
index b2d56dd483d9c8ad197b6a59071c2dd2378652da..89dc7d6bc1ccb94a8a65f06a45a1d35e18d8562c 100644 (file)
 #ifndef _I915_COMPONENT_H_
 #define _I915_COMPONENT_H_
 
+/* MAX_PORT is the number of port
+ * It must be sync with I915_MAX_PORTS defined i915_drv.h
+ * 5 should be enough as only HSW, BDW, SKL need such fix.
+ */
+#define MAX_PORTS 5
+
 struct i915_audio_component {
        struct device *dev;
+       /**
+        * @aud_sample_rate: the array of audio sample rate per port
+        */
+       int aud_sample_rate[MAX_PORTS];
 
        const struct i915_audio_component_ops {
                struct module *owner;
@@ -33,6 +43,13 @@ struct i915_audio_component {
                void (*put_power)(struct device *);
                void (*codec_wake_override)(struct device *, bool enable);
                int (*get_cdclk_freq)(struct device *);
+               /**
+                * @sync_audio_rate: set n/cts based on the sample rate
+                *
+                * Called from audio driver. After audio driver sets the
+                * sample rate, it will call this function to set n/cts
+                */
+               int (*sync_audio_rate)(struct device *, int port, int rate);
        } *ops;
 
        const struct i915_audio_component_audio_ops {
index 042e7b3b629637d468029cadac9e9419f7ae295e..a21413324a3f7bbb55a0f2e002d10f7b2211a7e5 100644 (file)
@@ -9,515 +9,7 @@
 #ifndef _DT_BINDINGS_INPUT_INPUT_H
 #define _DT_BINDINGS_INPUT_INPUT_H
 
-#define KEY_RESERVED           0
-#define KEY_ESC                        1
-#define KEY_1                  2
-#define KEY_2                  3
-#define KEY_3                  4
-#define KEY_4                  5
-#define KEY_5                  6
-#define KEY_6                  7
-#define KEY_7                  8
-#define KEY_8                  9
-#define KEY_9                  10
-#define KEY_0                  11
-#define KEY_MINUS              12
-#define KEY_EQUAL              13
-#define KEY_BACKSPACE          14
-#define KEY_TAB                        15
-#define KEY_Q                  16
-#define KEY_W                  17
-#define KEY_E                  18
-#define KEY_R                  19
-#define KEY_T                  20
-#define KEY_Y                  21
-#define KEY_U                  22
-#define KEY_I                  23
-#define KEY_O                  24
-#define KEY_P                  25
-#define KEY_LEFTBRACE          26
-#define KEY_RIGHTBRACE         27
-#define KEY_ENTER              28
-#define KEY_LEFTCTRL           29
-#define KEY_A                  30
-#define KEY_S                  31
-#define KEY_D                  32
-#define KEY_F                  33
-#define KEY_G                  34
-#define KEY_H                  35
-#define KEY_J                  36
-#define KEY_K                  37
-#define KEY_L                  38
-#define KEY_SEMICOLON          39
-#define KEY_APOSTROPHE         40
-#define KEY_GRAVE              41
-#define KEY_LEFTSHIFT          42
-#define KEY_BACKSLASH          43
-#define KEY_Z                  44
-#define KEY_X                  45
-#define KEY_C                  46
-#define KEY_V                  47
-#define KEY_B                  48
-#define KEY_N                  49
-#define KEY_M                  50
-#define KEY_COMMA              51
-#define KEY_DOT                        52
-#define KEY_SLASH              53
-#define KEY_RIGHTSHIFT         54
-#define KEY_KPASTERISK         55
-#define KEY_LEFTALT            56
-#define KEY_SPACE              57
-#define KEY_CAPSLOCK           58
-#define KEY_F1                 59
-#define KEY_F2                 60
-#define KEY_F3                 61
-#define KEY_F4                 62
-#define KEY_F5                 63
-#define KEY_F6                 64
-#define KEY_F7                 65
-#define KEY_F8                 66
-#define KEY_F9                 67
-#define KEY_F10                        68
-#define KEY_NUMLOCK            69
-#define KEY_SCROLLLOCK         70
-#define KEY_KP7                        71
-#define KEY_KP8                        72
-#define KEY_KP9                        73
-#define KEY_KPMINUS            74
-#define KEY_KP4                        75
-#define KEY_KP5                        76
-#define KEY_KP6                        77
-#define KEY_KPPLUS             78
-#define KEY_KP1                        79
-#define KEY_KP2                        80
-#define KEY_KP3                        81
-#define KEY_KP0                        82
-#define KEY_KPDOT              83
-
-#define KEY_ZENKAKUHANKAKU     85
-#define KEY_102ND              86
-#define KEY_F11                        87
-#define KEY_F12                        88
-#define KEY_RO                 89
-#define KEY_KATAKANA           90
-#define KEY_HIRAGANA           91
-#define KEY_HENKAN             92
-#define KEY_KATAKANAHIRAGANA   93
-#define KEY_MUHENKAN           94
-#define KEY_KPJPCOMMA          95
-#define KEY_KPENTER            96
-#define KEY_RIGHTCTRL          97
-#define KEY_KPSLASH            98
-#define KEY_SYSRQ              99
-#define KEY_RIGHTALT           100
-#define KEY_LINEFEED           101
-#define KEY_HOME               102
-#define KEY_UP                 103
-#define KEY_PAGEUP             104
-#define KEY_LEFT               105
-#define KEY_RIGHT              106
-#define KEY_END                        107
-#define KEY_DOWN               108
-#define KEY_PAGEDOWN           109
-#define KEY_INSERT             110
-#define KEY_DELETE             111
-#define KEY_MACRO              112
-#define KEY_MUTE               113
-#define KEY_VOLUMEDOWN         114
-#define KEY_VOLUMEUP           115
-#define KEY_POWER              116     /* SC System Power Down */
-#define KEY_KPEQUAL            117
-#define KEY_KPPLUSMINUS                118
-#define KEY_PAUSE              119
-#define KEY_SCALE              120     /* AL Compiz Scale (Expose) */
-
-#define KEY_KPCOMMA            121
-#define KEY_HANGEUL            122
-#define KEY_HANGUEL            KEY_HANGEUL
-#define KEY_HANJA              123
-#define KEY_YEN                        124
-#define KEY_LEFTMETA           125
-#define KEY_RIGHTMETA          126
-#define KEY_COMPOSE            127
-
-#define KEY_STOP               128     /* AC Stop */
-#define KEY_AGAIN              129
-#define KEY_PROPS              130     /* AC Properties */
-#define KEY_UNDO               131     /* AC Undo */
-#define KEY_FRONT              132
-#define KEY_COPY               133     /* AC Copy */
-#define KEY_OPEN               134     /* AC Open */
-#define KEY_PASTE              135     /* AC Paste */
-#define KEY_FIND               136     /* AC Search */
-#define KEY_CUT                        137     /* AC Cut */
-#define KEY_HELP               138     /* AL Integrated Help Center */
-#define KEY_MENU               139     /* Menu (show menu) */
-#define KEY_CALC               140     /* AL Calculator */
-#define KEY_SETUP              141
-#define KEY_SLEEP              142     /* SC System Sleep */
-#define KEY_WAKEUP             143     /* System Wake Up */
-#define KEY_FILE               144     /* AL Local Machine Browser */
-#define KEY_SENDFILE           145
-#define KEY_DELETEFILE         146
-#define KEY_XFER               147
-#define KEY_PROG1              148
-#define KEY_PROG2              149
-#define KEY_WWW                        150     /* AL Internet Browser */
-#define KEY_MSDOS              151
-#define KEY_COFFEE             152     /* AL Terminal Lock/Screensaver */
-#define KEY_SCREENLOCK         KEY_COFFEE
-#define KEY_DIRECTION          153
-#define KEY_CYCLEWINDOWS       154
-#define KEY_MAIL               155
-#define KEY_BOOKMARKS          156     /* AC Bookmarks */
-#define KEY_COMPUTER           157
-#define KEY_BACK               158     /* AC Back */
-#define KEY_FORWARD            159     /* AC Forward */
-#define KEY_CLOSECD            160
-#define KEY_EJECTCD            161
-#define KEY_EJECTCLOSECD       162
-#define KEY_NEXTSONG           163
-#define KEY_PLAYPAUSE          164
-#define KEY_PREVIOUSSONG       165
-#define KEY_STOPCD             166
-#define KEY_RECORD             167
-#define KEY_REWIND             168
-#define KEY_PHONE              169     /* Media Select Telephone */
-#define KEY_ISO                        170
-#define KEY_CONFIG             171     /* AL Consumer Control Configuration */
-#define KEY_HOMEPAGE           172     /* AC Home */
-#define KEY_REFRESH            173     /* AC Refresh */
-#define KEY_EXIT               174     /* AC Exit */
-#define KEY_MOVE               175
-#define KEY_EDIT               176
-#define KEY_SCROLLUP           177
-#define KEY_SCROLLDOWN         178
-#define KEY_KPLEFTPAREN                179
-#define KEY_KPRIGHTPAREN       180
-#define KEY_NEW                        181     /* AC New */
-#define KEY_REDO               182     /* AC Redo/Repeat */
-
-#define KEY_F13                        183
-#define KEY_F14                        184
-#define KEY_F15                        185
-#define KEY_F16                        186
-#define KEY_F17                        187
-#define KEY_F18                        188
-#define KEY_F19                        189
-#define KEY_F20                        190
-#define KEY_F21                        191
-#define KEY_F22                        192
-#define KEY_F23                        193
-#define KEY_F24                        194
-
-#define KEY_PLAYCD             200
-#define KEY_PAUSECD            201
-#define KEY_PROG3              202
-#define KEY_PROG4              203
-#define KEY_DASHBOARD          204     /* AL Dashboard */
-#define KEY_SUSPEND            205
-#define KEY_CLOSE              206     /* AC Close */
-#define KEY_PLAY               207
-#define KEY_FASTFORWARD                208
-#define KEY_BASSBOOST          209
-#define KEY_PRINT              210     /* AC Print */
-#define KEY_HP                 211
-#define KEY_CAMERA             212
-#define KEY_SOUND              213
-#define KEY_QUESTION           214
-#define KEY_EMAIL              215
-#define KEY_CHAT               216
-#define KEY_SEARCH             217
-#define KEY_CONNECT            218
-#define KEY_FINANCE            219     /* AL Checkbook/Finance */
-#define KEY_SPORT              220
-#define KEY_SHOP               221
-#define KEY_ALTERASE           222
-#define KEY_CANCEL             223     /* AC Cancel */
-#define KEY_BRIGHTNESSDOWN     224
-#define KEY_BRIGHTNESSUP       225
-#define KEY_MEDIA              226
-
-#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
-                                          outputs (Monitor/LCD/TV-out/etc) */
-#define KEY_KBDILLUMTOGGLE     228
-#define KEY_KBDILLUMDOWN       229
-#define KEY_KBDILLUMUP         230
-
-#define KEY_SEND               231     /* AC Send */
-#define KEY_REPLY              232     /* AC Reply */
-#define KEY_FORWARDMAIL                233     /* AC Forward Msg */
-#define KEY_SAVE               234     /* AC Save */
-#define KEY_DOCUMENTS          235
-
-#define KEY_BATTERY            236
-
-#define KEY_BLUETOOTH          237
-#define KEY_WLAN               238
-#define KEY_UWB                        239
-
-#define KEY_UNKNOWN            240
-
-#define KEY_VIDEO_NEXT         241     /* drive next video source */
-#define KEY_VIDEO_PREV         242     /* drive previous video source */
-#define KEY_BRIGHTNESS_CYCLE   243     /* brightness up, after max is min */
-#define KEY_BRIGHTNESS_ZERO    244     /* brightness off, use ambient */
-#define KEY_DISPLAY_OFF                245     /* display device to off state */
-
-#define KEY_WIMAX              246
-#define KEY_RFKILL             247     /* Key that controls all radios */
-
-#define KEY_MICMUTE            248     /* Mute / unmute the microphone */
-
-/* Code 255 is reserved for special needs of AT keyboard driver */
-
-#define BTN_MISC               0x100
-#define BTN_0                  0x100
-#define BTN_1                  0x101
-#define BTN_2                  0x102
-#define BTN_3                  0x103
-#define BTN_4                  0x104
-#define BTN_5                  0x105
-#define BTN_6                  0x106
-#define BTN_7                  0x107
-#define BTN_8                  0x108
-#define BTN_9                  0x109
-
-#define BTN_MOUSE              0x110
-#define BTN_LEFT               0x110
-#define BTN_RIGHT              0x111
-#define BTN_MIDDLE             0x112
-#define BTN_SIDE               0x113
-#define BTN_EXTRA              0x114
-#define BTN_FORWARD            0x115
-#define BTN_BACK               0x116
-#define BTN_TASK               0x117
-
-#define BTN_JOYSTICK           0x120
-#define BTN_TRIGGER            0x120
-#define BTN_THUMB              0x121
-#define BTN_THUMB2             0x122
-#define BTN_TOP                        0x123
-#define BTN_TOP2               0x124
-#define BTN_PINKIE             0x125
-#define BTN_BASE               0x126
-#define BTN_BASE2              0x127
-#define BTN_BASE3              0x128
-#define BTN_BASE4              0x129
-#define BTN_BASE5              0x12a
-#define BTN_BASE6              0x12b
-#define BTN_DEAD               0x12f
-
-#define BTN_GAMEPAD            0x130
-#define BTN_SOUTH              0x130
-#define BTN_A                  BTN_SOUTH
-#define BTN_EAST               0x131
-#define BTN_B                  BTN_EAST
-#define BTN_C                  0x132
-#define BTN_NORTH              0x133
-#define BTN_X                  BTN_NORTH
-#define BTN_WEST               0x134
-#define BTN_Y                  BTN_WEST
-#define BTN_Z                  0x135
-#define BTN_TL                 0x136
-#define BTN_TR                 0x137
-#define BTN_TL2                        0x138
-#define BTN_TR2                        0x139
-#define BTN_SELECT             0x13a
-#define BTN_START              0x13b
-#define BTN_MODE               0x13c
-#define BTN_THUMBL             0x13d
-#define BTN_THUMBR             0x13e
-
-#define BTN_DIGI               0x140
-#define BTN_TOOL_PEN           0x140
-#define BTN_TOOL_RUBBER                0x141
-#define BTN_TOOL_BRUSH         0x142
-#define BTN_TOOL_PENCIL                0x143
-#define BTN_TOOL_AIRBRUSH      0x144
-#define BTN_TOOL_FINGER                0x145
-#define BTN_TOOL_MOUSE         0x146
-#define BTN_TOOL_LENS          0x147
-#define BTN_TOOL_QUINTTAP      0x148   /* Five fingers on trackpad */
-#define BTN_TOUCH              0x14a
-#define BTN_STYLUS             0x14b
-#define BTN_STYLUS2            0x14c
-#define BTN_TOOL_DOUBLETAP     0x14d
-#define BTN_TOOL_TRIPLETAP     0x14e
-#define BTN_TOOL_QUADTAP       0x14f   /* Four fingers on trackpad */
-
-#define BTN_WHEEL              0x150
-#define BTN_GEAR_DOWN          0x150
-#define BTN_GEAR_UP            0x151
-
-#define KEY_OK                 0x160
-#define KEY_SELECT             0x161
-#define KEY_GOTO               0x162
-#define KEY_CLEAR              0x163
-#define KEY_POWER2             0x164
-#define KEY_OPTION             0x165
-#define KEY_INFO               0x166   /* AL OEM Features/Tips/Tutorial */
-#define KEY_TIME               0x167
-#define KEY_VENDOR             0x168
-#define KEY_ARCHIVE            0x169
-#define KEY_PROGRAM            0x16a   /* Media Select Program Guide */
-#define KEY_CHANNEL            0x16b
-#define KEY_FAVORITES          0x16c
-#define KEY_EPG                        0x16d
-#define KEY_PVR                        0x16e   /* Media Select Home */
-#define KEY_MHP                        0x16f
-#define KEY_LANGUAGE           0x170
-#define KEY_TITLE              0x171
-#define KEY_SUBTITLE           0x172
-#define KEY_ANGLE              0x173
-#define KEY_ZOOM               0x174
-#define KEY_MODE               0x175
-#define KEY_KEYBOARD           0x176
-#define KEY_SCREEN             0x177
-#define KEY_PC                 0x178   /* Media Select Computer */
-#define KEY_TV                 0x179   /* Media Select TV */
-#define KEY_TV2                        0x17a   /* Media Select Cable */
-#define KEY_VCR                        0x17b   /* Media Select VCR */
-#define KEY_VCR2               0x17c   /* VCR Plus */
-#define KEY_SAT                        0x17d   /* Media Select Satellite */
-#define KEY_SAT2               0x17e
-#define KEY_CD                 0x17f   /* Media Select CD */
-#define KEY_TAPE               0x180   /* Media Select Tape */
-#define KEY_RADIO              0x181
-#define KEY_TUNER              0x182   /* Media Select Tuner */
-#define KEY_PLAYER             0x183
-#define KEY_TEXT               0x184
-#define KEY_DVD                        0x185   /* Media Select DVD */
-#define KEY_AUX                        0x186
-#define KEY_MP3                        0x187
-#define KEY_AUDIO              0x188   /* AL Audio Browser */
-#define KEY_VIDEO              0x189   /* AL Movie Browser */
-#define KEY_DIRECTORY          0x18a
-#define KEY_LIST               0x18b
-#define KEY_MEMO               0x18c   /* Media Select Messages */
-#define KEY_CALENDAR           0x18d
-#define KEY_RED                        0x18e
-#define KEY_GREEN              0x18f
-#define KEY_YELLOW             0x190
-#define KEY_BLUE               0x191
-#define KEY_CHANNELUP          0x192   /* Channel Increment */
-#define KEY_CHANNELDOWN                0x193   /* Channel Decrement */
-#define KEY_FIRST              0x194
-#define KEY_LAST               0x195   /* Recall Last */
-#define KEY_AB                 0x196
-#define KEY_NEXT               0x197
-#define KEY_RESTART            0x198
-#define KEY_SLOW               0x199
-#define KEY_SHUFFLE            0x19a
-#define KEY_BREAK              0x19b
-#define KEY_PREVIOUS           0x19c
-#define KEY_DIGITS             0x19d
-#define KEY_TEEN               0x19e
-#define KEY_TWEN               0x19f
-#define KEY_VIDEOPHONE         0x1a0   /* Media Select Video Phone */
-#define KEY_GAMES              0x1a1   /* Media Select Games */
-#define KEY_ZOOMIN             0x1a2   /* AC Zoom In */
-#define KEY_ZOOMOUT            0x1a3   /* AC Zoom Out */
-#define KEY_ZOOMRESET          0x1a4   /* AC Zoom */
-#define KEY_WORDPROCESSOR      0x1a5   /* AL Word Processor */
-#define KEY_EDITOR             0x1a6   /* AL Text Editor */
-#define KEY_SPREADSHEET                0x1a7   /* AL Spreadsheet */
-#define KEY_GRAPHICSEDITOR     0x1a8   /* AL Graphics Editor */
-#define KEY_PRESENTATION       0x1a9   /* AL Presentation App */
-#define KEY_DATABASE           0x1aa   /* AL Database App */
-#define KEY_NEWS               0x1ab   /* AL Newsreader */
-#define KEY_VOICEMAIL          0x1ac   /* AL Voicemail */
-#define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
-#define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
-#define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
-#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
-#define KEY_LOGOFF             0x1b1   /* AL Logoff */
-
-#define KEY_DOLLAR             0x1b2
-#define KEY_EURO               0x1b3
-
-#define KEY_FRAMEBACK          0x1b4   /* Consumer - transport controls */
-#define KEY_FRAMEFORWARD       0x1b5
-#define KEY_CONTEXT_MENU       0x1b6   /* GenDesc - system context menu */
-#define KEY_MEDIA_REPEAT       0x1b7   /* Consumer - transport control */
-#define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
-#define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
-#define KEY_IMAGES             0x1ba   /* AL Image Browser */
-
-#define KEY_DEL_EOL            0x1c0
-#define KEY_DEL_EOS            0x1c1
-#define KEY_INS_LINE           0x1c2
-#define KEY_DEL_LINE           0x1c3
-
-#define KEY_FN                 0x1d0
-#define KEY_FN_ESC             0x1d1
-#define KEY_FN_F1              0x1d2
-#define KEY_FN_F2              0x1d3
-#define KEY_FN_F3              0x1d4
-#define KEY_FN_F4              0x1d5
-#define KEY_FN_F5              0x1d6
-#define KEY_FN_F6              0x1d7
-#define KEY_FN_F7              0x1d8
-#define KEY_FN_F8              0x1d9
-#define KEY_FN_F9              0x1da
-#define KEY_FN_F10             0x1db
-#define KEY_FN_F11             0x1dc
-#define KEY_FN_F12             0x1dd
-#define KEY_FN_1               0x1de
-#define KEY_FN_2               0x1df
-#define KEY_FN_D               0x1e0
-#define KEY_FN_E               0x1e1
-#define KEY_FN_F               0x1e2
-#define KEY_FN_S               0x1e3
-#define KEY_FN_B               0x1e4
-
-#define KEY_BRL_DOT1           0x1f1
-#define KEY_BRL_DOT2           0x1f2
-#define KEY_BRL_DOT3           0x1f3
-#define KEY_BRL_DOT4           0x1f4
-#define KEY_BRL_DOT5           0x1f5
-#define KEY_BRL_DOT6           0x1f6
-#define KEY_BRL_DOT7           0x1f7
-#define KEY_BRL_DOT8           0x1f8
-#define KEY_BRL_DOT9           0x1f9
-#define KEY_BRL_DOT10          0x1fa
-
-#define KEY_NUMERIC_0          0x200   /* used by phones, remote controls, */
-#define KEY_NUMERIC_1          0x201   /* and other keypads */
-#define KEY_NUMERIC_2          0x202
-#define KEY_NUMERIC_3          0x203
-#define KEY_NUMERIC_4          0x204
-#define KEY_NUMERIC_5          0x205
-#define KEY_NUMERIC_6          0x206
-#define KEY_NUMERIC_7          0x207
-#define KEY_NUMERIC_8          0x208
-#define KEY_NUMERIC_9          0x209
-#define KEY_NUMERIC_STAR       0x20a
-#define KEY_NUMERIC_POUND      0x20b
-
-#define KEY_CAMERA_FOCUS       0x210
-#define KEY_WPS_BUTTON         0x211   /* WiFi Protected Setup key */
-
-#define KEY_TOUCHPAD_TOGGLE    0x212   /* Request switch touchpad on or off */
-#define KEY_TOUCHPAD_ON                0x213
-#define KEY_TOUCHPAD_OFF       0x214
-
-#define KEY_CAMERA_ZOOMIN      0x215
-#define KEY_CAMERA_ZOOMOUT     0x216
-#define KEY_CAMERA_UP          0x217
-#define KEY_CAMERA_DOWN                0x218
-#define KEY_CAMERA_LEFT                0x219
-#define KEY_CAMERA_RIGHT       0x21a
-
-#define KEY_ATTENDANT_ON       0x21b
-#define KEY_ATTENDANT_OFF      0x21c
-#define KEY_ATTENDANT_TOGGLE   0x21d   /* Attendant call on or off */
-#define KEY_LIGHTS_TOGGLE      0x21e   /* Reading light on or off */
-
-#define BTN_DPAD_UP            0x220
-#define BTN_DPAD_DOWN          0x221
-#define BTN_DPAD_LEFT          0x222
-#define BTN_DPAD_RIGHT         0x223
+#include "linux-event-codes.h"
 
 #define MATRIX_KEY(row, col, code)     \
        ((((row) & 0xFF) << 24) | (((col) & 0xFF) << 16) | ((code) & 0xFFFF))
diff --git a/include/dt-bindings/input/linux-event-codes.h b/include/dt-bindings/input/linux-event-codes.h
new file mode 120000 (symlink)
index 0000000..693bbcd
--- /dev/null
@@ -0,0 +1 @@
+../../uapi/linux/input-event-codes.h
\ No newline at end of file
index 4fef65e5702396bab72e501d158b2c514d279127..744b997d6a94ae01852c190d195f89fa3c4124ae 100644 (file)
@@ -42,6 +42,7 @@ struct aer_capability_regs {
 int pci_enable_pcie_error_reporting(struct pci_dev *dev);
 int pci_disable_pcie_error_reporting(struct pci_dev *dev);
 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
+int pci_cleanup_aer_error_status_regs(struct pci_dev *dev);
 #else
 static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
 {
@@ -55,6 +56,10 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 {
        return -EINVAL;
 }
+static inline int pci_cleanup_aer_error_status_regs(struct pci_dev *dev)
+{
+       return -EINVAL;
+}
 #endif
 
 void cper_print_aer(struct pci_dev *dev, int cper_severity,
diff --git a/include/linux/blkpg.h b/include/linux/blkpg.h
new file mode 100644 (file)
index 0000000..bef124f
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _LINUX_BLKPG_H
+#define _LINUX_BLKPG_H
+
+/*
+ * Partition table and disk geometry handling
+ */
+
+#include <linux/compat.h>
+#include <uapi/linux/blkpg.h>
+
+#ifdef CONFIG_COMPAT
+/* For 32-bit/64-bit compatibility of struct blkpg_ioctl_arg */
+struct blkpg_compat_ioctl_arg {
+       compat_int_t op;
+       compat_int_t flags;
+       compat_int_t datalen;
+       compat_uptr_t data;
+};
+#endif
+
+#endif /* _LINUX_BLKPG_H */
diff --git a/include/linux/count_zeros.h b/include/linux/count_zeros.h
new file mode 100644 (file)
index 0000000..363da78
--- /dev/null
@@ -0,0 +1,57 @@
+/* Count leading and trailing zeros functions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_BITOPS_COUNT_ZEROS_H_
+#define _LINUX_BITOPS_COUNT_ZEROS_H_
+
+#include <asm/bitops.h>
+
+/**
+ * count_leading_zeros - Count the number of zeros from the MSB back
+ * @x: The value
+ *
+ * Count the number of leading zeros from the MSB going towards the LSB in @x.
+ *
+ * If the MSB of @x is set, the result is 0.
+ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
+ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
+ */
+static inline int count_leading_zeros(unsigned long x)
+{
+       if (sizeof(x) == 4)
+               return BITS_PER_LONG - fls(x);
+       else
+               return BITS_PER_LONG - fls64(x);
+}
+
+#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
+
+/**
+ * count_trailing_zeros - Count the number of zeros from the LSB forwards
+ * @x: The value
+ *
+ * Count the number of trailing zeros from the LSB going towards the MSB in @x.
+ *
+ * If the LSB of @x is set, the result is 0.
+ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
+ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
+ */
+static inline int count_trailing_zeros(unsigned long x)
+{
+#define COUNT_TRAILING_ZEROS_0 (-1)
+
+       if (sizeof(x) == 4)
+               return ffs(x);
+       else
+               return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
+}
+
+#endif /* _LINUX_BITOPS_COUNT_ZEROS_H_ */
index 6cd8c0ee4b6f89a9ab93b67515cb6e214e108071..eae6548efbf060d9a2ec21bd716b0c0e2b6f2be7 100644 (file)
@@ -263,7 +263,18 @@ static inline void ftrace_kill(void) { }
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #ifdef CONFIG_STACK_TRACER
+
+#define STACK_TRACE_ENTRIES 500
+
+struct stack_trace;
+
+extern unsigned stack_trace_index[];
+extern struct stack_trace stack_trace_max;
+extern unsigned long stack_trace_max_size;
+extern arch_spinlock_t stack_trace_max_lock;
+
 extern int stack_tracer_enabled;
+void stack_trace_print(void);
 int
 stack_trace_sysctl(struct ctl_table *table, int write,
                   void __user *buffer, size_t *lenp,
index f17980de26629fbf65365047a0cfe8ce6034b53e..251a1d382e2325a17e0acb169d6e111589cf7444 100644 (file)
@@ -698,8 +698,8 @@ struct hid_driver {
        int (*input_mapped)(struct hid_device *hdev,
                        struct hid_input *hidinput, struct hid_field *field,
                        struct hid_usage *usage, unsigned long **bit, int *max);
-       void (*input_configured)(struct hid_device *hdev,
-                                struct hid_input *hidinput);
+       int (*input_configured)(struct hid_device *hdev,
+                               struct hid_input *hidinput);
        void (*feature_mapping)(struct hid_device *hdev,
                        struct hid_field *field,
                        struct hid_usage *usage);
index 82ce323b998692b9c3d0b95b762605e51147cafd..1e967694e9a525deb811a03608ebecc91cabaab3 100644 (file)
@@ -469,6 +469,8 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke);
 int input_set_keycode(struct input_dev *dev,
                      const struct input_keymap_entry *ke);
 
+void input_enable_softrepeat(struct input_dev *dev, int delay, int period);
+
 extern struct class input_class;
 
 /**
diff --git a/include/linux/input/edt-ft5x06.h b/include/linux/input/edt-ft5x06.h
deleted file mode 100644 (file)
index 8a1e0d1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _EDT_FT5X06_H
-#define _EDT_FT5X06_H
-
-/*
- * Copyright (c) 2012 Simon Budig, <simon.budig@kernelconcepts.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.
- */
-
-struct edt_ft5x06_platform_data {
-       int irq_pin;
-       int reset_pin;
-
-       /* startup defaults for operational parameters */
-       bool use_parameters;
-       u8 gain;
-       u8 threshold;
-       u8 offset;
-       u8 report_rate;
-};
-
-#endif /* _EDT_FT5X06_H */
diff --git a/include/linux/io-64-nonatomic-hi-lo.h b/include/linux/io-64-nonatomic-hi-lo.h
new file mode 100644 (file)
index 0000000..11d7e84
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _LINUX_IO_64_NONATOMIC_HI_LO_H_
+#define _LINUX_IO_64_NONATOMIC_HI_LO_H_
+
+#include <linux/io.h>
+#include <asm-generic/int-ll64.h>
+
+static inline __u64 hi_lo_readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       high = readl(p + 1);
+       low = readl(p);
+
+       return low + ((u64)high << 32);
+}
+
+static inline void hi_lo_writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val >> 32, addr + 4);
+       writel(val, addr);
+}
+
+#ifndef readq
+#define readq hi_lo_readq
+#endif
+
+#ifndef writeq
+#define writeq hi_lo_writeq
+#endif
+
+#endif /* _LINUX_IO_64_NONATOMIC_HI_LO_H_ */
diff --git a/include/linux/io-64-nonatomic-lo-hi.h b/include/linux/io-64-nonatomic-lo-hi.h
new file mode 100644 (file)
index 0000000..1a4315f
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _LINUX_IO_64_NONATOMIC_LO_HI_H_
+#define _LINUX_IO_64_NONATOMIC_LO_HI_H_
+
+#include <linux/io.h>
+#include <asm-generic/int-ll64.h>
+
+static inline __u64 lo_hi_readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+
+static inline void lo_hi_writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr + 4);
+}
+
+#ifndef readq
+#define readq lo_hi_readq
+#endif
+
+#ifndef writeq
+#define writeq lo_hi_writeq
+#endif
+
+#endif /* _LINUX_IO_64_NONATOMIC_LO_HI_H_ */
index df07e78487d560f1e2d96b5e5249a57a080c4ed2..65407f6c9120ae25e814ea98e60d170f035c8ace 100644 (file)
@@ -278,6 +278,7 @@ typedef struct journal_superblock_s
 /* 0x0400 */
 } journal_superblock_t;
 
+/* Use the jbd2_{has,set,clear}_feature_* helpers; these will be removed */
 #define JBD2_HAS_COMPAT_FEATURE(j,mask)                                        \
        ((j)->j_format_version >= 2 &&                                  \
         ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
@@ -288,7 +289,7 @@ typedef struct journal_superblock_s
        ((j)->j_format_version >= 2 &&                                  \
         ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
 
-#define JBD2_FEATURE_COMPAT_CHECKSUM   0x00000001
+#define JBD2_FEATURE_COMPAT_CHECKSUM           0x00000001
 
 #define JBD2_FEATURE_INCOMPAT_REVOKE           0x00000001
 #define JBD2_FEATURE_INCOMPAT_64BIT            0x00000002
@@ -296,6 +297,8 @@ typedef struct journal_superblock_s
 #define JBD2_FEATURE_INCOMPAT_CSUM_V2          0x00000008
 #define JBD2_FEATURE_INCOMPAT_CSUM_V3          0x00000010
 
+/* See "journal feature predicate functions" below */
+
 /* Features known to this kernel version: */
 #define JBD2_KNOWN_COMPAT_FEATURES     JBD2_FEATURE_COMPAT_CHECKSUM
 #define JBD2_KNOWN_ROCOMPAT_FEATURES   0
@@ -1034,6 +1037,69 @@ struct journal_s
        __u32 j_csum_seed;
 };
 
+/* journal feature predicate functions */
+#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \
+static inline bool jbd2_has_feature_##name(journal_t *j) \
+{ \
+       return ((j)->j_format_version >= 2 && \
+               ((j)->j_superblock->s_feature_compat & \
+                cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname)) != 0); \
+} \
+static inline void jbd2_set_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_compat |= \
+               cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \
+} \
+static inline void jbd2_clear_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_compat &= \
+               ~cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \
+}
+
+#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
+static inline bool jbd2_has_feature_##name(journal_t *j) \
+{ \
+       return ((j)->j_format_version >= 2 && \
+               ((j)->j_superblock->s_feature_ro_compat & \
+                cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname)) != 0); \
+} \
+static inline void jbd2_set_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_ro_compat |= \
+               cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \
+} \
+static inline void jbd2_clear_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_ro_compat &= \
+               ~cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \
+}
+
+#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \
+static inline bool jbd2_has_feature_##name(journal_t *j) \
+{ \
+       return ((j)->j_format_version >= 2 && \
+               ((j)->j_superblock->s_feature_incompat & \
+                cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname)) != 0); \
+} \
+static inline void jbd2_set_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_incompat |= \
+               cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \
+} \
+static inline void jbd2_clear_feature_##name(journal_t *j) \
+{ \
+       (j)->j_superblock->s_feature_incompat &= \
+               ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \
+}
+
+JBD2_FEATURE_COMPAT_FUNCS(checksum,            CHECKSUM)
+
+JBD2_FEATURE_INCOMPAT_FUNCS(revoke,            REVOKE)
+JBD2_FEATURE_INCOMPAT_FUNCS(64bit,             64BIT)
+JBD2_FEATURE_INCOMPAT_FUNCS(async_commit,      ASYNC_COMMIT)
+JBD2_FEATURE_INCOMPAT_FUNCS(csum2,             CSUM_V2)
+JBD2_FEATURE_INCOMPAT_FUNCS(csum3,             CSUM_V3)
+
 /*
  * Journal flag definitions
  */
@@ -1046,6 +1112,7 @@ struct journal_s
 #define JBD2_ABORT_ON_SYNCDATA_ERR     0x040   /* Abort the journal on file
                                                 * data write error in ordered
                                                 * mode */
+#define JBD2_REC_ERR   0x080   /* The errno in the sb has been recorded */
 
 /*
  * Function declarations for the journaling transaction and buffer
@@ -1338,13 +1405,17 @@ static inline int tid_geq(tid_t x, tid_t y)
 extern int jbd2_journal_blocks_per_page(struct inode *inode);
 extern size_t journal_tag_bytes(journal_t *journal);
 
+static inline bool jbd2_journal_has_csum_v2or3_feature(journal_t *j)
+{
+       return jbd2_has_feature_csum2(j) || jbd2_has_feature_csum3(j);
+}
+
 static inline int jbd2_journal_has_csum_v2or3(journal_t *journal)
 {
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) ||
-           JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3))
-               return 1;
+       WARN_ON_ONCE(jbd2_journal_has_csum_v2or3_feature(journal) &&
+                    journal->j_chksum_driver == NULL);
 
-       return 0;
+       return journal->j_chksum_driver != NULL;
 }
 
 /*
@@ -1444,4 +1515,7 @@ static inline tid_t  jbd2_get_latest_transaction(journal_t *journal)
 
 #endif /* __KERNEL__ */
 
+#define EFSBADCRC      EBADMSG         /* Bad CRC detected */
+#define EFSCORRUPTED   EUCLEAN         /* Filesystem is corrupted */
+
 #endif /* _LINUX_JBD2_H */
index 81f6e427ba6bbb9b65f52a5d5937c39aee0c0125..5430374659734ae74ea27e8fb28a126976482b26 100644 (file)
@@ -49,6 +49,7 @@
 #define LOOP_CTRL_MINOR                237
 #define VHOST_NET_MINOR                238
 #define UHID_MINOR             239
+#define USERIO_MINOR           240
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index 5a8677bafe0408bad140320471e38c100e4bf33a..7501626ab5293414c29df692edb6fa7122871c84 100644 (file)
@@ -214,6 +214,8 @@ enum {
        MLX4_DEV_CAP_FLAG2_IGNORE_FCS           = 1LL <<  28,
        MLX4_DEV_CAP_FLAG2_PHV_EN               = 1LL <<  29,
        MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN      = 1LL <<  30,
+       MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB = 1ULL << 31,
+       MLX4_DEV_CAP_FLAG2_LB_SRC_CHK           = 1ULL << 32,
 };
 
 enum {
index de45a51b3f041d28e644cc6a0ce011d6cd2d4fb6..fe052e234906da97e88206d0b05db2442bced61f 100644 (file)
@@ -135,7 +135,10 @@ struct mlx4_rss_context {
 
 struct mlx4_qp_path {
        u8                      fl;
-       u8                      vlan_control;
+       union {
+               u8                      vlan_control;
+               u8                      control;
+       };
        u8                      disable_pkey_check;
        u8                      pkey_index;
        u8                      counter_index;
@@ -156,9 +159,16 @@ struct mlx4_qp_path {
 };
 
 enum { /* fl */
-       MLX4_FL_CV      = 1 << 6,
-       MLX4_FL_ETH_HIDE_CQE_VLAN       = 1 << 2
+       MLX4_FL_CV      = 1 << 6,
+       MLX4_FL_ETH_HIDE_CQE_VLAN       = 1 << 2,
+       MLX4_FL_ETH_SRC_CHECK_MC_LB     = 1 << 1,
+       MLX4_FL_ETH_SRC_CHECK_UC_LB     = 1 << 0,
 };
+
+enum { /* control */
+       MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER      = 1 << 7,
+};
+
 enum { /* vlan_control */
        MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED      = 1 << 6,
        MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED = 1 << 5, /* 802.1p priority tag */
@@ -254,6 +264,8 @@ enum {
        MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE               = 14 + 32,
        MLX4_UPD_QP_PATH_MASK_IF_COUNTER_INDEX          = 15 + 32,
        MLX4_UPD_QP_PATH_MASK_FVL_RX                    = 16 + 32,
+       MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_UC_LB       = 18 + 32,
+       MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB       = 19 + 32,
 };
 
 enum { /* param3 */
@@ -436,11 +448,13 @@ enum mlx4_update_qp_attr {
        MLX4_UPDATE_QP_VSD              = 1 << 1,
        MLX4_UPDATE_QP_RATE_LIMIT       = 1 << 2,
        MLX4_UPDATE_QP_QOS_VPORT        = 1 << 3,
-       MLX4_UPDATE_QP_SUPPORTED_ATTRS  = (1 << 4) - 1
+       MLX4_UPDATE_QP_ETH_SRC_CHECK_MC_LB      = 1 << 4,
+       MLX4_UPDATE_QP_SUPPORTED_ATTRS  = (1 << 5) - 1
 };
 
 enum mlx4_update_qp_params_flags {
-       MLX4_UPDATE_QP_PARAMS_FLAGS_VSD_ENABLE          = 1 << 0,
+       MLX4_UPDATE_QP_PARAMS_FLAGS_ETH_CHECK_MC_LB     = 1 << 0,
+       MLX4_UPDATE_QP_PARAMS_FLAGS_VSD_ENABLE          = 1 << 1,
 };
 
 struct mlx4_update_qp_params {
index 6975cbf1435ba6aa8afc999b4b398dadae5133f6..64f36e09a7901f1a1f4f382395cacbbffa2c89e6 100644 (file)
@@ -219,6 +219,14 @@ struct serio_device_id {
        __u8 proto;
 };
 
+struct hda_device_id {
+       __u32 vendor_id;
+       __u32 rev_id;
+       __u8 api_version;
+       const char *name;
+       unsigned long driver_data;
+};
+
 /*
  * Struct used for matching a device
  */
index 0b4460374020fd98e40248c990eb6110493a21be..f71a25e5fd25b574bceaf9b397b62e0913419067 100644 (file)
@@ -163,6 +163,8 @@ struct msi_controller {
 
        int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev,
                         struct msi_desc *desc);
+       int (*setup_irqs)(struct msi_controller *chip, struct pci_dev *dev,
+                         int nvec, int type);
        void (*teardown_irq)(struct msi_controller *chip, unsigned int irq);
 };
 
index 272f42952f3424aa43953b7e3a50b925a93bd465..5a9d1d4c2487fc2cf8f08489f317bf60df93b06f 100644 (file)
@@ -504,16 +504,16 @@ struct nand_ecc_ctrl {
        int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
        int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required);
+                       const uint8_t *buf, int oob_required, int page);
        int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
        int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t offs, uint32_t len, uint8_t *buf, int page);
        int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t offset, uint32_t data_len,
-                       const uint8_t *data_buf, int oob_required);
+                       const uint8_t *data_buf, int oob_required, int page);
        int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required);
+                       const uint8_t *buf, int oob_required, int page);
        int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        int page);
        int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
@@ -544,7 +544,7 @@ struct nand_buffers {
  *                     flash device
  * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the
  *                     flash device.
- * @dn:                        [BOARDSPECIFIC] device node describing this instance
+ * @flash_node:                [BOARDSPECIFIC] device node describing this instance
  * @read_byte:         [REPLACEABLE] read one byte from the chip
  * @read_word:         [REPLACEABLE] read one word from the chip
  * @write_byte:                [REPLACEABLE] write a single byte to the chip on the
@@ -556,10 +556,6 @@ struct nand_buffers {
  * @block_markbad:     [REPLACEABLE] mark a block bad
  * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific function for controlling
  *                     ALE/CLE/nCE. Also used to write command and address
- * @init_size:         [BOARDSPECIFIC] hardwarespecific function for setting
- *                     mtd->oobsize, mtd->writesize and so on.
- *                     @id_data contains the 8 bytes values of NAND_CMD_READID.
- *                     Return with the bus width.
  * @dev_ready:         [BOARDSPECIFIC] hardwarespecific function for accessing
  *                     device ready/busy line. If set to NULL no access to
  *                     ready/busy is available and the ready/busy information
@@ -647,7 +643,7 @@ struct nand_chip {
        void __iomem *IO_ADDR_R;
        void __iomem *IO_ADDR_W;
 
-       struct device_node *dn;
+       struct device_node *flash_node;
 
        uint8_t (*read_byte)(struct mtd_info *mtd);
        u16 (*read_word)(struct mtd_info *mtd);
@@ -658,8 +654,6 @@ struct nand_chip {
        int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
        int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
        void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
-       int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
-                       u8 *id_data);
        int (*dev_ready)(struct mtd_info *mtd);
        void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
                        int page_addr);
@@ -1030,4 +1024,9 @@ struct nand_sdr_timings {
 
 /* get timing characteristics from ONFI timing mode. */
 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+                               void *ecc, int ecclen,
+                               void *extraoob, int extraooblen,
+                               int threshold);
 #endif /* __LINUX_MTD_NAND_H */
index e5409524bb0aeca355b5bd44ce2bddb03ceca5da..c8723b62c4cd286aa7b6b382507dbb25cd975ab1 100644 (file)
 #ifndef __LINUX_MTD_SPI_NOR_H
 #define __LINUX_MTD_SPI_NOR_H
 
+#include <linux/bitops.h>
+#include <linux/mtd/cfi.h>
+
+/*
+ * Manufacturer IDs
+ *
+ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
+ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
+ */
+#define SNOR_MFR_ATMEL         CFI_MFR_ATMEL
+#define SNOR_MFR_INTEL         CFI_MFR_INTEL
+#define SNOR_MFR_MICRON                CFI_MFR_ST /* ST Micro <--> Micron */
+#define SNOR_MFR_MACRONIX      CFI_MFR_MACRONIX
+#define SNOR_MFR_SPANSION      CFI_MFR_AMD
+#define SNOR_MFR_SST           CFI_MFR_SST
+#define SNOR_MFR_WINBOND       0xef
+
 /*
  * Note on opcode nomenclature: some opcodes have a format like
  * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
 #define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
 
 /* Status Register bits. */
-#define SR_WIP                 1       /* Write in progress */
-#define SR_WEL                 2       /* Write enable latch */
+#define SR_WIP                 BIT(0)  /* Write in progress */
+#define SR_WEL                 BIT(1)  /* Write enable latch */
 /* meaning of other SR_* bits may differ between vendors */
-#define SR_BP0                 4       /* Block protect 0 */
-#define SR_BP1                 8       /* Block protect 1 */
-#define SR_BP2                 0x10    /* Block protect 2 */
-#define SR_SRWD                        0x80    /* SR write protect */
+#define SR_BP0                 BIT(2)  /* Block protect 0 */
+#define SR_BP1                 BIT(3)  /* Block protect 1 */
+#define SR_BP2                 BIT(4)  /* Block protect 2 */
+#define SR_SRWD                        BIT(7)  /* SR write protect */
 
-#define SR_QUAD_EN_MX          0x40    /* Macronix Quad I/O */
+#define SR_QUAD_EN_MX          BIT(6)  /* Macronix Quad I/O */
 
 /* Enhanced Volatile Configuration Register bits */
-#define EVCR_QUAD_EN_MICRON    0x80    /* Micron Quad I/O */
+#define EVCR_QUAD_EN_MICRON    BIT(7)  /* Micron Quad I/O */
 
 /* Flag Status Register bits */
-#define FSR_READY              0x80
+#define FSR_READY              BIT(7)
 
 /* Configuration Register bits. */
-#define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
+#define CR_QUAD_EN_SPAN                BIT(1)  /* Spansion Quad I/O */
 
 enum read_mode {
        SPI_NOR_NORMAL = 0,
@@ -87,33 +104,6 @@ enum read_mode {
        SPI_NOR_QUAD,
 };
 
-/**
- * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
- * @wren:              command for "Write Enable", or 0x00 for not required
- * @cmd:               command for operation
- * @cmd_pins:          number of pins to send @cmd (1, 2, 4)
- * @addr:              address for operation
- * @addr_pins:         number of pins to send @addr (1, 2, 4)
- * @addr_width:                number of address bytes
- *                     (3,4, or 0 for address not required)
- * @mode:              mode data
- * @mode_pins:         number of pins to send @mode (1, 2, 4)
- * @mode_cycles:       number of mode cycles (0 for mode not required)
- * @dummy_cycles:      number of dummy cycles (0 for dummy not required)
- */
-struct spi_nor_xfer_cfg {
-       u8              wren;
-       u8              cmd;
-       u8              cmd_pins;
-       u32             addr;
-       u8              addr_pins;
-       u8              addr_width;
-       u8              mode;
-       u8              mode_pins;
-       u8              mode_cycles;
-       u8              dummy_cycles;
-};
-
 #define SPI_NOR_MAX_CMD_SIZE   8
 enum spi_nor_ops {
        SPI_NOR_OPS_READ = 0,
@@ -127,11 +117,14 @@ enum spi_nor_option_flags {
        SNOR_F_USE_FSR          = BIT(0),
 };
 
+struct mtd_info;
+
 /**
  * struct spi_nor - Structure for defining a the SPI NOR layer
  * @mtd:               point to a mtd_info structure
  * @lock:              the lock for the read/write/erase/lock/unlock operations
  * @dev:               point to a spi device, or a spi nor controller device.
+ * @flash_node:                point to a device node describing this flash instance.
  * @page_size:         the page size of the SPI NOR
  * @addr_width:                number of address bytes
  * @erase_opcode:      the opcode for erasing a sector
@@ -141,28 +134,28 @@ enum spi_nor_option_flags {
  * @flash_read:                the mode of the read
  * @sst_write_second:  used by the SST write operation
  * @flags:             flag options for the current SPI-NOR (SNOR_F_*)
- * @cfg:               used by the read_xfer/write_xfer
  * @cmd_buf:           used by the write_reg
  * @prepare:           [OPTIONAL] do some preparations for the
  *                     read/write/erase/lock/unlock operations
  * @unprepare:         [OPTIONAL] do some post work after the
  *                     read/write/erase/lock/unlock operations
- * @read_xfer:         [OPTIONAL] the read fundamental primitive
- * @write_xfer:                [OPTIONAL] the writefundamental primitive
  * @read_reg:          [DRIVER-SPECIFIC] read out the register
  * @write_reg:         [DRIVER-SPECIFIC] write data to the register
  * @read:              [DRIVER-SPECIFIC] read data from the SPI NOR
  * @write:             [DRIVER-SPECIFIC] write data to the SPI NOR
  * @erase:             [DRIVER-SPECIFIC] erase a sector of the SPI NOR
  *                     at the offset @offs
- * @lock:              [FLASH-SPECIFIC] lock a region of the SPI NOR
- * @unlock:            [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_lock:                [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock:      [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
+ *                     completely locked
  * @priv:              the private data
  */
 struct spi_nor {
-       struct mtd_info         *mtd;
+       struct mtd_info         mtd;
        struct mutex            lock;
        struct device           *dev;
+       struct device_node      *flash_node;
        u32                     page_size;
        u8                      addr_width;
        u8                      erase_opcode;
@@ -172,18 +165,12 @@ struct spi_nor {
        enum read_mode          flash_read;
        bool                    sst_write_second;
        u32                     flags;
-       struct spi_nor_xfer_cfg cfg;
        u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
 
        int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
        void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
-       int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-                        u8 *buf, size_t len);
-       int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-                         u8 *buf, size_t len);
        int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
-       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int write_enable);
+       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
 
        int (*read)(struct spi_nor *nor, loff_t from,
                        size_t len, size_t *retlen, u_char *read_buf);
@@ -193,6 +180,7 @@ struct spi_nor {
 
        int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
+       int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 
        void *priv;
 };
index 65d969246a4d02e1ee8854451c923d5003941d31..039f2eec49ced0ae1c638354d1a34c924cebde51 100644 (file)
@@ -51,6 +51,7 @@ extern struct irq_domain *of_msi_get_domain(struct device *dev,
                                            enum irq_domain_bus_token token);
 extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev,
                                                       u32 rid);
+extern void of_msi_configure(struct device *dev, struct device_node *np);
 #else
 static inline int of_irq_count(struct device_node *dev)
 {
@@ -80,31 +81,27 @@ static inline struct irq_domain *of_msi_map_get_device_domain(struct device *dev
 {
        return NULL;
 }
+static inline void of_msi_configure(struct device *dev, struct device_node *np)
+{
+}
 #endif
 
-#if defined(CONFIG_OF)
+#if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC)
 /*
  * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
  * implements it differently.  However, the prototype is the same for all,
  * so declare it here regardless of the CONFIG_OF_IRQ setting.
  */
 extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
-extern struct device_node *of_irq_find_parent(struct device_node *child);
-extern void of_msi_configure(struct device *dev, struct device_node *np);
 u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
 
-#else /* !CONFIG_OF */
+#else /* !CONFIG_OF && !CONFIG_SPARC */
 static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
                                                int index)
 {
        return 0;
 }
 
-static inline void *of_irq_find_parent(struct device_node *child)
-{
-       return NULL;
-}
-
 static inline u32 of_msi_map_rid(struct device *dev,
                                 struct device_node *msi_np, u32 rid_in)
 {
index 29fd3fe1c035d10361e9926ee879d9b6c4c70662..38c0533a33598bc8891af481589687c282739b37 100644 (file)
@@ -17,6 +17,7 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 void of_pci_dma_configure(struct pci_dev *pci_dev);
+void of_pci_check_probe_only(void);
 #else
 static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
 {
@@ -53,6 +54,8 @@ of_get_pci_domain_nr(struct device_node *node)
 }
 
 static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
+
+static inline void of_pci_check_probe_only(void) { }
 #endif
 
 #if defined(CONFIG_OF_ADDRESS)
index e90eb22de6286df6be1ed07ed8f37aa6ab7810b4..e828e7b4afec67a4b9f083cfa65c2ff3cffe8571 100644 (file)
@@ -820,6 +820,7 @@ void pci_bus_add_device(struct pci_dev *dev);
 void pci_read_bridge_bases(struct pci_bus *child);
 struct resource *pci_find_parent_resource(const struct pci_dev *dev,
                                          struct resource *res);
+struct pci_dev *pci_find_pcie_root_port(struct pci_dev *dev);
 u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin);
 int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
 u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
@@ -1192,6 +1193,17 @@ void pci_unregister_driver(struct pci_driver *dev);
        module_driver(__pci_driver, pci_register_driver, \
                       pci_unregister_driver)
 
+/**
+ * builtin_pci_driver() - Helper macro for registering a PCI driver
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for PCI drivers which do not do anything special in their
+ * init code. This eliminates a lot of boilerplate. Each driver may only
+ * use this macro once, and calling it replaces device_initcall(...)
+ */
+#define builtin_pci_driver(__pci_driver) \
+       builtin_driver(__pci_driver, pci_register_driver)
+
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
                  unsigned int vendor, unsigned int device,
index ac4ea2e641c7c6ecb52f01414593e7db62fa7a0e..394d15597dc75a2ec923dc4daa64dd1acd4c2d66 100644 (file)
@@ -4,30 +4,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-struct pxa3xx_nand_timing {
-       unsigned int    tCH;  /* Enable signal hold time */
-       unsigned int    tCS;  /* Enable signal setup time */
-       unsigned int    tWH;  /* ND_nWE high duration */
-       unsigned int    tWP;  /* ND_nWE pulse time */
-       unsigned int    tRH;  /* ND_nRE high duration */
-       unsigned int    tRP;  /* ND_nRE pulse width */
-       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
-       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
-       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
-};
-
-struct pxa3xx_nand_flash {
-       char            *name;
-       uint32_t        chip_id;
-       unsigned int    page_per_block; /* Pages per block (PG_PER_BLK) */
-       unsigned int    page_size;      /* Page size in bytes (PAGE_SZ) */
-       unsigned int    flash_width;    /* Width of Flash memory (DWIDTH_M) */
-       unsigned int    dfc_width;      /* Width of flash controller(DWIDTH_C) */
-       unsigned int    num_blocks;     /* Number of physical blocks in Flash */
-
-       struct pxa3xx_nand_timing *timing;      /* NAND Flash timing */
-};
-
 /*
  * Current pxa3xx_nand controller has two chip select which
  * both be workable.
@@ -63,9 +39,6 @@ struct pxa3xx_nand_platform_data {
 
        const struct mtd_partition              *parts[NUM_CHIP_SELECT];
        unsigned int                            nr_parts[NUM_CHIP_SELECT];
-
-       const struct pxa3xx_nand_flash *        flash;
-       size_t                                  num_flash;
 };
 
 extern void pxa3xx_set_nand_info(struct pxa3xx_nand_platform_data *info);
index e2c13cd863bdc5b41a65731a4e55018aee3762f4..4acc552e92790c98f4e89721cc488d8441a289da 100644 (file)
@@ -154,8 +154,8 @@ ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
 }
 #endif
 
-int ring_buffer_empty(struct ring_buffer *buffer);
-int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu);
+bool ring_buffer_empty(struct ring_buffer *buffer);
+bool ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu);
 
 void ring_buffer_record_disable(struct ring_buffer *buffer);
 void ring_buffer_record_enable(struct ring_buffer *buffer);
index 3f594dce571650c76253a785e8720490a7c0f80e..fe3dc64e5aebf95b88508644ba83a14bffa451ee 100644 (file)
@@ -8,9 +8,10 @@ struct rotary_encoder_platform_data {
        unsigned int gpio_b;
        unsigned int inverted_a;
        unsigned int inverted_b;
+       unsigned int steps_per_period;
        bool relative_axis;
        bool rollover;
-       bool half_period;
+       bool wakeup_source;
 };
 
 #endif /* __ROTARY_ENCODER_H__ */
index 7ccc961f33e933fc25eae43dd74fbd888920d2d7..1e4438ea2380dd07e79f3d8011445900edea7437 100644 (file)
@@ -105,11 +105,9 @@ struct svc_rdma_chunk_sge {
 };
 struct svc_rdma_fastreg_mr {
        struct ib_mr *mr;
-       void *kva;
-       struct ib_fast_reg_page_list *page_list;
-       int page_list_len;
+       struct scatterlist *sg;
+       int sg_nents;
        unsigned long access_flags;
-       unsigned long map_len;
        enum dma_data_direction direction;
        struct list_head frmr_list;
 };
index ed27917cabc9d95ff3b30b115f1f661626edba17..429fdfc3baf59e018d0e198062f894642af8a5bc 100644 (file)
@@ -168,13 +168,12 @@ struct ring_buffer_event *
 trace_current_buffer_lock_reserve(struct ring_buffer **current_buffer,
                                  int type, unsigned long len,
                                  unsigned long flags, int pc);
-void trace_current_buffer_unlock_commit(struct ring_buffer *buffer,
-                                       struct ring_buffer_event *event,
-                                       unsigned long flags, int pc);
-void trace_buffer_unlock_commit(struct ring_buffer *buffer,
+void trace_buffer_unlock_commit(struct trace_array *tr,
+                               struct ring_buffer *buffer,
                                struct ring_buffer_event *event,
                                unsigned long flags, int pc);
-void trace_buffer_unlock_commit_regs(struct ring_buffer *buffer,
+void trace_buffer_unlock_commit_regs(struct trace_array *tr,
+                                    struct ring_buffer *buffer,
                                     struct ring_buffer_event *event,
                                     unsigned long flags, int pc,
                                     struct pt_regs *regs);
@@ -329,6 +328,7 @@ enum {
        EVENT_FILE_FL_SOFT_DISABLED_BIT,
        EVENT_FILE_FL_TRIGGER_MODE_BIT,
        EVENT_FILE_FL_TRIGGER_COND_BIT,
+       EVENT_FILE_FL_PID_FILTER_BIT,
 };
 
 /*
@@ -342,6 +342,7 @@ enum {
  *                   tracepoint may be enabled)
  *  TRIGGER_MODE  - When set, invoke the triggers associated with the event
  *  TRIGGER_COND  - When set, one or more triggers has an associated filter
+ *  PID_FILTER    - When set, the event is filtered based on pid
  */
 enum {
        EVENT_FILE_FL_ENABLED           = (1 << EVENT_FILE_FL_ENABLED_BIT),
@@ -352,6 +353,7 @@ enum {
        EVENT_FILE_FL_SOFT_DISABLED     = (1 << EVENT_FILE_FL_SOFT_DISABLED_BIT),
        EVENT_FILE_FL_TRIGGER_MODE      = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT),
        EVENT_FILE_FL_TRIGGER_COND      = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT),
+       EVENT_FILE_FL_PID_FILTER        = (1 << EVENT_FILE_FL_PID_FILTER_BIT),
 };
 
 struct trace_event_file {
@@ -430,6 +432,8 @@ extern enum event_trigger_type event_triggers_call(struct trace_event_file *file
 extern void event_triggers_post_call(struct trace_event_file *file,
                                     enum event_trigger_type tt);
 
+bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
+
 /**
  * trace_trigger_soft_disabled - do triggers and test if soft disabled
  * @file: The file pointer of the event to test
@@ -449,6 +453,8 @@ trace_trigger_soft_disabled(struct trace_event_file *file)
                        event_triggers_call(file, NULL);
                if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
                        return true;
+               if (eflags & EVENT_FILE_FL_PID_FILTER)
+                       return trace_event_ignore_this_pid(file);
        }
        return false;
 }
@@ -508,7 +514,7 @@ event_trigger_unlock_commit(struct trace_event_file *file,
        enum event_trigger_type tt = ETT_NONE;
 
        if (!__event_trigger_test_discard(file, buffer, event, entry, &tt))
-               trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+               trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc);
 
        if (tt)
                event_triggers_post_call(file, tt);
@@ -540,7 +546,7 @@ event_trigger_unlock_commit_regs(struct trace_event_file *file,
        enum event_trigger_type tt = ETT_NONE;
 
        if (!__event_trigger_test_discard(file, buffer, event, entry, &tt))
-               trace_buffer_unlock_commit_regs(buffer, event,
+               trace_buffer_unlock_commit_regs(file->tr, buffer, event,
                                                irq_flags, pc, regs);
 
        if (tt)
index a5f7f3ecafa3a77123531ca2a07a01b086906db0..696a339c592c831942a8fcdc9b2e5ea963599747 100644 (file)
@@ -26,6 +26,7 @@ struct notifier_block;
 struct tracepoint_func {
        void *func;
        void *data;
+       int prio;
 };
 
 struct tracepoint {
@@ -42,9 +43,14 @@ struct trace_enum_map {
        unsigned long           enum_value;
 };
 
+#define TRACEPOINT_DEFAULT_PRIO        10
+
 extern int
 tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
 extern int
+tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data,
+                              int prio);
+extern int
 tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
 extern void
 for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv),
@@ -111,7 +117,18 @@ extern void syscall_unregfunc(void);
 #define TP_ARGS(args...)       args
 #define TP_CONDITION(args...)  args
 
-#ifdef CONFIG_TRACEPOINTS
+/*
+ * Individual subsystem my have a separate configuration to
+ * enable their tracepoints. By default, this file will create
+ * the tracepoints if CONFIG_TRACEPOINT is defined. If a subsystem
+ * wants to be able to disable its tracepoints from being created
+ * it can define NOTRACE before including the tracepoint headers.
+ */
+#if defined(CONFIG_TRACEPOINTS) && !defined(NOTRACE)
+#define TRACEPOINTS_ENABLED
+#endif
+
+#ifdef TRACEPOINTS_ENABLED
 
 /*
  * it_func[0] is never NULL because there is at least one element in the array
@@ -167,10 +184,11 @@ extern void syscall_unregfunc(void);
  * structure. Force alignment to the same alignment as the section start.
  *
  * When lockdep is enabled, we make sure to always do the RCU portions of
- * the tracepoint code, regardless of whether tracing is on or we match the
- * condition.  This lets us find RCU issues triggered with tracepoints even
- * when this tracepoint is off.  This code has no purpose other than poking
- * RCU a bit.
+ * the tracepoint code, regardless of whether tracing is on. However,
+ * don't check if the condition is false, due to interaction with idle
+ * instrumentation. This lets us find RCU issues triggered with tracepoints
+ * even when this tracepoint is off. This code has no purpose other than
+ * poking RCU a bit.
  */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
        extern struct tracepoint __tracepoint_##name;                   \
@@ -196,6 +214,13 @@ extern void syscall_unregfunc(void);
                                                (void *)probe, data);   \
        }                                                               \
        static inline int                                               \
+       register_trace_prio_##name(void (*probe)(data_proto), void *data,\
+                                  int prio)                            \
+       {                                                               \
+               return tracepoint_probe_register_prio(&__tracepoint_##name, \
+                                             (void *)probe, data, prio); \
+       }                                                               \
+       static inline int                                               \
        unregister_trace_##name(void (*probe)(data_proto), void *data)  \
        {                                                               \
                return tracepoint_probe_unregister(&__tracepoint_##name,\
@@ -234,7 +259,7 @@ extern void syscall_unregfunc(void);
 #define EXPORT_TRACEPOINT_SYMBOL(name)                                 \
        EXPORT_SYMBOL(__tracepoint_##name)
 
-#else /* !CONFIG_TRACEPOINTS */
+#else /* !TRACEPOINTS_ENABLED */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
        static inline void trace_##name(proto)                          \
        { }                                                             \
@@ -266,7 +291,7 @@ extern void syscall_unregfunc(void);
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
-#endif /* CONFIG_TRACEPOINTS */
+#endif /* TRACEPOINTS_ENABLED */
 
 #ifdef CONFIG_TRACING
 /**
index fde33ac6b58a1e4eccb52512055f546d3a59e2a6..11528591d0d714f3ea1004566cb799952a9ca5bd 100644 (file)
@@ -47,6 +47,7 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_pack.h>
 #include <net/ipv6.h>
+#include <net/net_namespace.h>
 
 struct rdma_addr_client {
        atomic_t refcount;
@@ -64,6 +65,16 @@ void rdma_addr_register_client(struct rdma_addr_client *client);
  */
 void rdma_addr_unregister_client(struct rdma_addr_client *client);
 
+/**
+ * struct rdma_dev_addr - Contains resolved RDMA hardware addresses
+ * @src_dev_addr:      Source MAC address.
+ * @dst_dev_addr:      Destination MAC address.
+ * @broadcast:         Broadcast address of the device.
+ * @dev_type:          The interface hardware type of the device.
+ * @bound_dev_if:      An optional device interface index.
+ * @transport:         The transport type used.
+ * @net:               Network namespace containing the bound_dev_if net_dev.
+ */
 struct rdma_dev_addr {
        unsigned char src_dev_addr[MAX_ADDR_LEN];
        unsigned char dst_dev_addr[MAX_ADDR_LEN];
@@ -71,11 +82,14 @@ struct rdma_dev_addr {
        unsigned short dev_type;
        int bound_dev_if;
        enum rdma_transport_type transport;
+       struct net *net;
 };
 
 /**
  * rdma_translate_ip - Translate a local IP address to an RDMA hardware
  *   address.
+ *
+ * The dev_addr->net field must be initialized.
  */
 int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
                      u16 *vlan_id);
@@ -90,7 +104,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
  * @dst_addr: The destination address to resolve.
  * @addr: A reference to a data location that will receive the resolved
  *   addresses.  The data location must remain valid until the callback has
- *   been invoked.
+ *   been invoked. The net field of the addr struct must be valid.
  * @timeout_ms: Amount of time to wait for the address resolution to complete.
  * @callback: Call invoked once address resolution has completed, timed out,
  *   or been canceled.  A status of 0 indicates success.
@@ -112,7 +126,7 @@ int rdma_addr_size(struct sockaddr *addr);
 
 int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id);
 int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
-                              u8 *smac, u16 *vlan_id);
+                              u8 *smac, u16 *vlan_id, int if_index);
 
 static inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr)
 {
index bd92130f4ac5803a60e0c058bc19d26faca9f948..269a27cf0a46f37c7fd9fdc3fc24df2d5070c2d2 100644 (file)
@@ -43,6 +43,8 @@
  * @port_num: The port number of the device to query.
  * @index: The index into the cached GID table to query.
  * @gid: The GID value found at the specified index.
+ * @attr: The GID attribute found at the specified index (only in RoCE).
+ *   NULL means ignore (output parameter).
  *
  * ib_get_cached_gid() fetches the specified GID table entry stored in
  * the local software cache.
 int ib_get_cached_gid(struct ib_device    *device,
                      u8                   port_num,
                      int                  index,
-                     union ib_gid        *gid);
+                     union ib_gid        *gid,
+                     struct ib_gid_attr  *attr);
 
 /**
  * ib_find_cached_gid - Returns the port number and GID table index where
  *   a specified GID value occurs.
  * @device: The device to query.
  * @gid: The GID value to search for.
+ * @ndev: In RoCE, the net device of the device. NULL means ignore.
  * @port_num: The port number of the device where the GID value was found.
  * @index: The index into the cached GID table where the GID was found.  This
  *   parameter may be NULL.
@@ -64,11 +68,39 @@ int ib_get_cached_gid(struct ib_device    *device,
  * ib_find_cached_gid() searches for the specified GID value in
  * the local software cache.
  */
-int ib_find_cached_gid(struct ib_device   *device,
+int ib_find_cached_gid(struct ib_device *device,
                       const union ib_gid *gid,
-                      u8                 *port_num,
-                      u16                *index);
+                      struct net_device *ndev,
+                      u8               *port_num,
+                      u16              *index);
 
+/**
+ * ib_find_cached_gid_by_port - Returns the GID table index where a specified
+ * GID value occurs
+ * @device: The device to query.
+ * @gid: The GID value to search for.
+ * @port_num: The port number of the device where the GID value sould be
+ *   searched.
+ * @ndev: In RoCE, the net device of the device. Null means ignore.
+ * @index: The index into the cached GID table where the GID was found.  This
+ *   parameter may be NULL.
+ *
+ * ib_find_cached_gid() searches for the specified GID value in
+ * the local software cache.
+ */
+int ib_find_cached_gid_by_port(struct ib_device *device,
+                              const union ib_gid *gid,
+                              u8               port_num,
+                              struct net_device *ndev,
+                              u16              *index);
+
+int ib_find_gid_by_filter(struct ib_device *device,
+                         const union ib_gid *gid,
+                         u8 port_num,
+                         bool (*filter)(const union ib_gid *gid,
+                                        const struct ib_gid_attr *,
+                                        void *),
+                         void *context, u16 *index);
 /**
  * ib_get_cached_pkey - Returns a cached PKey table entry
  * @device: The device to query.
index 709a5331e6b9d2ff04ba262d377b53f6819426c9..e99d8f9a4551d9889501c645e04139fd0f32a3f8 100644 (file)
@@ -76,7 +76,7 @@ enum {
        IB_OPCODE_UC                                = 0x20,
        IB_OPCODE_RD                                = 0x40,
        IB_OPCODE_UD                                = 0x60,
-       /* per IBTA 3.1 Table 38, A10.3.2 */
+       /* per IBTA 1.3 vol 1 Table 38, A10.3.2 */
        IB_OPCODE_CNP                               = 0x80,
 
        /* operations -- just used to define real constants */
index 7e071a6abb34cb977ad26c304bddfcf22a89903a..301969552d0a51e34dcd872daa303a6339721916 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/compiler.h>
 
 #include <linux/atomic.h>
+#include <linux/netdevice.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_mad.h>
@@ -154,11 +155,18 @@ struct ib_sa_path_rec {
        u8           packet_life_time_selector;
        u8           packet_life_time;
        u8           preference;
-       u8           smac[ETH_ALEN];
        u8           dmac[ETH_ALEN];
-       u16          vlan_id;
+       /* ignored in IB */
+       int          ifindex;
+       /* ignored in IB */
+       struct net  *net;
 };
 
+static inline struct net_device *ib_get_ndev_from_path(struct ib_sa_path_rec *rec)
+{
+       return rec->net ? dev_get_by_index(rec->net, rec->ifindex) : NULL;
+}
+
 #define IB_SA_MCMEMBER_REC_MGID                                IB_SA_COMP_MASK( 0)
 #define IB_SA_MCMEMBER_REC_PORT_GID                    IB_SA_COMP_MASK( 1)
 #define IB_SA_MCMEMBER_REC_QKEY                                IB_SA_COMP_MASK( 2)
index 7845fae6f2df1bd7c362174c104b6efbaaf62547..9a68a19532ba57c27042cec499843f3cebfa273c 100644 (file)
@@ -137,6 +137,8 @@ enum ib_device_cap_flags {
        IB_DEVICE_BLOCK_MULTICAST_LOOPBACK = (1<<22),
        IB_DEVICE_MEM_WINDOW_TYPE_2A    = (1<<23),
        IB_DEVICE_MEM_WINDOW_TYPE_2B    = (1<<24),
+       IB_DEVICE_RC_IP_CSUM            = (1<<25),
+       IB_DEVICE_RAW_IP_CSUM           = (1<<26),
        IB_DEVICE_MANAGED_FLOW_STEERING = (1<<29),
        IB_DEVICE_SIGNATURE_HANDOVER    = (1<<30),
        IB_DEVICE_ON_DEMAND_PAGING      = (1<<31),
@@ -474,7 +476,7 @@ enum ib_event_type {
        IB_EVENT_GID_CHANGE,
 };
 
-__attribute_const__ const char *ib_event_msg(enum ib_event_type event);
+const char *__attribute_const__ ib_event_msg(enum ib_event_type event);
 
 struct ib_event {
        struct ib_device        *device;
@@ -697,7 +699,6 @@ struct ib_ah_attr {
        u8                      ah_flags;
        u8                      port_num;
        u8                      dmac[ETH_ALEN];
-       u16                     vlan_id;
 };
 
 enum ib_wc_status {
@@ -725,7 +726,7 @@ enum ib_wc_status {
        IB_WC_GENERAL_ERR
 };
 
-__attribute_const__ const char *ib_wc_status_msg(enum ib_wc_status status);
+const char *__attribute_const__ ib_wc_status_msg(enum ib_wc_status status);
 
 enum ib_wc_opcode {
        IB_WC_SEND,
@@ -736,7 +737,7 @@ enum ib_wc_opcode {
        IB_WC_BIND_MW,
        IB_WC_LSO,
        IB_WC_LOCAL_INV,
-       IB_WC_FAST_REG_MR,
+       IB_WC_REG_MR,
        IB_WC_MASKED_COMP_SWAP,
        IB_WC_MASKED_FETCH_ADD,
 /*
@@ -873,7 +874,6 @@ enum ib_qp_create_flags {
        IB_QP_CREATE_RESERVED_END               = 1 << 31,
 };
 
-
 /*
  * Note: users may not call ib_close_qp or ib_destroy_qp from the event_handler
  * callback to destroy the passed in QP.
@@ -957,10 +957,10 @@ enum ib_qp_attr_mask {
        IB_QP_PATH_MIG_STATE            = (1<<18),
        IB_QP_CAP                       = (1<<19),
        IB_QP_DEST_QPN                  = (1<<20),
-       IB_QP_SMAC                      = (1<<21),
-       IB_QP_ALT_SMAC                  = (1<<22),
-       IB_QP_VID                       = (1<<23),
-       IB_QP_ALT_VID                   = (1<<24),
+       IB_QP_RESERVED1                 = (1<<21),
+       IB_QP_RESERVED2                 = (1<<22),
+       IB_QP_RESERVED3                 = (1<<23),
+       IB_QP_RESERVED4                 = (1<<24),
 };
 
 enum ib_qp_state {
@@ -1010,10 +1010,6 @@ struct ib_qp_attr {
        u8                      rnr_retry;
        u8                      alt_port_num;
        u8                      alt_timeout;
-       u8                      smac[ETH_ALEN];
-       u8                      alt_smac[ETH_ALEN];
-       u16                     vlan_id;
-       u16                     alt_vlan_id;
 };
 
 enum ib_wr_opcode {
@@ -1028,7 +1024,7 @@ enum ib_wr_opcode {
        IB_WR_SEND_WITH_INV,
        IB_WR_RDMA_READ_WITH_INV,
        IB_WR_LOCAL_INV,
-       IB_WR_FAST_REG_MR,
+       IB_WR_REG_MR,
        IB_WR_MASKED_ATOMIC_CMP_AND_SWP,
        IB_WR_MASKED_ATOMIC_FETCH_AND_ADD,
        IB_WR_BIND_MW,
@@ -1066,12 +1062,6 @@ struct ib_sge {
        u32     lkey;
 };
 
-struct ib_fast_reg_page_list {
-       struct ib_device       *device;
-       u64                    *page_list;
-       unsigned int            max_page_list_len;
-};
-
 /**
  * struct ib_mw_bind_info - Parameters for a memory window bind operation.
  * @mr: A memory region to bind the memory window to.
@@ -1100,54 +1090,89 @@ struct ib_send_wr {
                __be32          imm_data;
                u32             invalidate_rkey;
        } ex;
-       union {
-               struct {
-                       u64     remote_addr;
-                       u32     rkey;
-               } rdma;
-               struct {
-                       u64     remote_addr;
-                       u64     compare_add;
-                       u64     swap;
-                       u64     compare_add_mask;
-                       u64     swap_mask;
-                       u32     rkey;
-               } atomic;
-               struct {
-                       struct ib_ah *ah;
-                       void   *header;
-                       int     hlen;
-                       int     mss;
-                       u32     remote_qpn;
-                       u32     remote_qkey;
-                       u16     pkey_index; /* valid for GSI only */
-                       u8      port_num;   /* valid for DR SMPs on switch only */
-               } ud;
-               struct {
-                       u64                             iova_start;
-                       struct ib_fast_reg_page_list   *page_list;
-                       unsigned int                    page_shift;
-                       unsigned int                    page_list_len;
-                       u32                             length;
-                       int                             access_flags;
-                       u32                             rkey;
-               } fast_reg;
-               struct {
-                       struct ib_mw            *mw;
-                       /* The new rkey for the memory window. */
-                       u32                      rkey;
-                       struct ib_mw_bind_info   bind_info;
-               } bind_mw;
-               struct {
-                       struct ib_sig_attrs    *sig_attrs;
-                       struct ib_mr           *sig_mr;
-                       int                     access_flags;
-                       struct ib_sge          *prot;
-               } sig_handover;
-       } wr;
-       u32                     xrc_remote_srq_num;     /* XRC TGT QPs only */
 };
 
+struct ib_rdma_wr {
+       struct ib_send_wr       wr;
+       u64                     remote_addr;
+       u32                     rkey;
+};
+
+static inline struct ib_rdma_wr *rdma_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_rdma_wr, wr);
+}
+
+struct ib_atomic_wr {
+       struct ib_send_wr       wr;
+       u64                     remote_addr;
+       u64                     compare_add;
+       u64                     swap;
+       u64                     compare_add_mask;
+       u64                     swap_mask;
+       u32                     rkey;
+};
+
+static inline struct ib_atomic_wr *atomic_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_atomic_wr, wr);
+}
+
+struct ib_ud_wr {
+       struct ib_send_wr       wr;
+       struct ib_ah            *ah;
+       void                    *header;
+       int                     hlen;
+       int                     mss;
+       u32                     remote_qpn;
+       u32                     remote_qkey;
+       u16                     pkey_index; /* valid for GSI only */
+       u8                      port_num;   /* valid for DR SMPs on switch only */
+};
+
+static inline struct ib_ud_wr *ud_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_ud_wr, wr);
+}
+
+struct ib_reg_wr {
+       struct ib_send_wr       wr;
+       struct ib_mr            *mr;
+       u32                     key;
+       int                     access;
+};
+
+static inline struct ib_reg_wr *reg_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_reg_wr, wr);
+}
+
+struct ib_bind_mw_wr {
+       struct ib_send_wr       wr;
+       struct ib_mw            *mw;
+       /* The new rkey for the memory window. */
+       u32                     rkey;
+       struct ib_mw_bind_info  bind_info;
+};
+
+static inline struct ib_bind_mw_wr *bind_mw_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_bind_mw_wr, wr);
+}
+
+struct ib_sig_handover_wr {
+       struct ib_send_wr       wr;
+       struct ib_sig_attrs    *sig_attrs;
+       struct ib_mr           *sig_mr;
+       int                     access_flags;
+       struct ib_sge          *prot;
+};
+
+static inline struct ib_sig_handover_wr *sig_handover_wr(struct ib_send_wr *wr)
+{
+       return container_of(wr, struct ib_sig_handover_wr, wr);
+}
+
 struct ib_recv_wr {
        struct ib_recv_wr      *next;
        u64                     wr_id;
@@ -1334,6 +1359,9 @@ struct ib_mr {
        struct ib_uobject *uobject;
        u32                lkey;
        u32                rkey;
+       u64                iova;
+       u32                length;
+       unsigned int       page_size;
        atomic_t           usecnt; /* count number of MWs */
 };
 
@@ -1718,9 +1746,9 @@ struct ib_device {
        struct ib_mr *             (*alloc_mr)(struct ib_pd *pd,
                                               enum ib_mr_type mr_type,
                                               u32 max_num_sg);
-       struct ib_fast_reg_page_list * (*alloc_fast_reg_page_list)(struct ib_device *device,
-                                                                  int page_list_len);
-       void                       (*free_fast_reg_page_list)(struct ib_fast_reg_page_list *page_list);
+       int                        (*map_mr_sg)(struct ib_mr *mr,
+                                               struct scatterlist *sg,
+                                               int sg_nents);
        int                        (*rereg_phys_mr)(struct ib_mr *mr,
                                                    int mr_rereg_mask,
                                                    struct ib_pd *pd,
@@ -2176,7 +2204,8 @@ static inline bool rdma_cap_roce_gid_table(const struct ib_device *device,
 }
 
 int ib_query_gid(struct ib_device *device,
-                u8 port_num, int index, union ib_gid *gid);
+                u8 port_num, int index, union ib_gid *gid,
+                struct ib_gid_attr *attr);
 
 int ib_query_pkey(struct ib_device *device,
                  u8 port_num, u16 index, u16 *pkey);
@@ -2190,7 +2219,7 @@ int ib_modify_port(struct ib_device *device,
                   struct ib_port_modify *port_modify);
 
 int ib_find_gid(struct ib_device *device, union ib_gid *gid,
-               u8 *port_num, u16 *index);
+               struct net_device *ndev, u8 *port_num, u16 *index);
 
 int ib_find_pkey(struct ib_device *device,
                 u8 port_num, u16 pkey, u16 *index);
@@ -2828,33 +2857,6 @@ struct ib_mr *ib_alloc_mr(struct ib_pd *pd,
                          enum ib_mr_type mr_type,
                          u32 max_num_sg);
 
-/**
- * ib_alloc_fast_reg_page_list - Allocates a page list array
- * @device - ib device pointer.
- * @page_list_len - size of the page list array to be allocated.
- *
- * This allocates and returns a struct ib_fast_reg_page_list * and a
- * page_list array that is at least page_list_len in size.  The actual
- * size is returned in max_page_list_len.  The caller is responsible
- * for initializing the contents of the page_list array before posting
- * a send work request with the IB_WC_FAST_REG_MR opcode.
- *
- * The page_list array entries must be translated using one of the
- * ib_dma_*() functions just like the addresses passed to
- * ib_map_phys_fmr().  Once the ib_post_send() is issued, the struct
- * ib_fast_reg_page_list must not be modified by the caller until the
- * IB_WC_FAST_REG_MR work request completes.
- */
-struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(
-                               struct ib_device *device, int page_list_len);
-
-/**
- * ib_free_fast_reg_page_list - Deallocates a previously allocated
- *   page list array.
- * @page_list - struct ib_fast_reg_page_list pointer to be deallocated.
- */
-void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list);
-
 /**
  * ib_update_fast_reg_key - updates the key portion of the fast_reg MR
  *   R_Key and L_Key.
@@ -3023,4 +3025,28 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, u8 port,
                                            u16 pkey, const union ib_gid *gid,
                                            const struct sockaddr *addr);
 
+int ib_map_mr_sg(struct ib_mr *mr,
+                struct scatterlist *sg,
+                int sg_nents,
+                unsigned int page_size);
+
+static inline int
+ib_map_mr_sg_zbva(struct ib_mr *mr,
+                 struct scatterlist *sg,
+                 int sg_nents,
+                 unsigned int page_size)
+{
+       int n;
+
+       n = ib_map_mr_sg(mr, sg, sg_nents, page_size);
+       mr->iova = 0;
+
+       return n;
+}
+
+int ib_sg_to_pages(struct ib_mr *mr,
+                  struct scatterlist *sgl,
+                  int sg_nents,
+                  int (*set_page)(struct ib_mr *, u64));
+
 #endif /* IB_VERBS_H */
index c92522c192d26df9401d061121fb743935ef9b45..afe44fde72a56599cb0dd1674078210a78438ae4 100644 (file)
@@ -62,7 +62,7 @@ enum rdma_cm_event_type {
        RDMA_CM_EVENT_TIMEWAIT_EXIT
 };
 
-__attribute_const__ const char *rdma_event_msg(enum rdma_cm_event_type event);
+const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event);
 
 enum rdma_port_space {
        RDMA_PS_SDP   = 0x0001,
@@ -160,13 +160,17 @@ struct rdma_cm_id {
 /**
  * rdma_create_id - Create an RDMA identifier.
  *
+ * @net: The network namespace in which to create the new id.
  * @event_handler: User callback invoked to report events associated with the
  *   returned rdma_id.
  * @context: User specified context associated with the id.
  * @ps: RDMA port space.
  * @qp_type: type of queue pair associated with the id.
+ *
+ * The id holds a reference on the network namespace until it is destroyed.
  */
-struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
+struct rdma_cm_id *rdma_create_id(struct net *net,
+                                 rdma_cm_event_handler event_handler,
                                  void *context, enum rdma_port_space ps,
                                  enum ib_qp_type qp_type);
 
index 673f5c39cbf28d975cf5022bc3e1b3f934df1fbb..e7eac897999504a6bdb0fc317d74c8ad7e6785a7 100644 (file)
@@ -44,9 +44,6 @@ struct da7213_platform_data {
        enum da7213_dmic_data_sel dmic_data_sel;
        enum da7213_dmic_samplephase dmic_samplephase;
        enum da7213_dmic_clk_rate dmic_clk_rate;
-
-       /* MCLK squaring config */
-       bool mclk_squaring;
 };
 
 #endif /* _DA7213_PDATA_H */
diff --git a/include/sound/da7219-aad.h b/include/sound/da7219-aad.h
new file mode 100644 (file)
index 0000000..17802fb
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * da7219-aad.h - DA7322 ASoC Codec AAD Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_AAD_PDATA_H
+#define __DA7219_AAD_PDATA_H
+
+enum da7219_aad_micbias_pulse_lvl {
+       DA7219_AAD_MICBIAS_PULSE_LVL_OFF = 0,
+       DA7219_AAD_MICBIAS_PULSE_LVL_2_8V = 6,
+       DA7219_AAD_MICBIAS_PULSE_LVL_2_9V,
+};
+
+enum da7219_aad_btn_cfg {
+       DA7219_AAD_BTN_CFG_2MS = 1,
+       DA7219_AAD_BTN_CFG_5MS,
+       DA7219_AAD_BTN_CFG_10MS,
+       DA7219_AAD_BTN_CFG_50MS,
+       DA7219_AAD_BTN_CFG_100MS,
+       DA7219_AAD_BTN_CFG_200MS,
+       DA7219_AAD_BTN_CFG_500MS,
+};
+
+enum da7219_aad_mic_det_thr {
+       DA7219_AAD_MIC_DET_THR_200_OHMS = 0,
+       DA7219_AAD_MIC_DET_THR_500_OHMS,
+       DA7219_AAD_MIC_DET_THR_750_OHMS,
+       DA7219_AAD_MIC_DET_THR_1000_OHMS,
+};
+
+enum da7219_aad_jack_ins_deb {
+       DA7219_AAD_JACK_INS_DEB_5MS = 0,
+       DA7219_AAD_JACK_INS_DEB_10MS,
+       DA7219_AAD_JACK_INS_DEB_20MS,
+       DA7219_AAD_JACK_INS_DEB_50MS,
+       DA7219_AAD_JACK_INS_DEB_100MS,
+       DA7219_AAD_JACK_INS_DEB_200MS,
+       DA7219_AAD_JACK_INS_DEB_500MS,
+       DA7219_AAD_JACK_INS_DEB_1S,
+};
+
+enum da7219_aad_jack_det_rate {
+       DA7219_AAD_JACK_DET_RATE_32_64MS = 0,
+       DA7219_AAD_JACK_DET_RATE_64_128MS,
+       DA7219_AAD_JACK_DET_RATE_128_256MS,
+       DA7219_AAD_JACK_DET_RATE_256_512MS,
+};
+
+enum da7219_aad_jack_rem_deb {
+       DA7219_AAD_JACK_REM_DEB_1MS = 0,
+       DA7219_AAD_JACK_REM_DEB_5MS,
+       DA7219_AAD_JACK_REM_DEB_10MS,
+       DA7219_AAD_JACK_REM_DEB_20MS,
+};
+
+enum da7219_aad_btn_avg {
+       DA7219_AAD_BTN_AVG_1 = 0,
+       DA7219_AAD_BTN_AVG_2,
+       DA7219_AAD_BTN_AVG_4,
+       DA7219_AAD_BTN_AVG_8,
+};
+
+enum da7219_aad_adc_1bit_rpt {
+       DA7219_AAD_ADC_1BIT_RPT_1 = 0,
+       DA7219_AAD_ADC_1BIT_RPT_2,
+       DA7219_AAD_ADC_1BIT_RPT_4,
+       DA7219_AAD_ADC_1BIT_RPT_8,
+};
+
+struct da7219_aad_pdata {
+       int irq;
+
+       enum da7219_aad_micbias_pulse_lvl micbias_pulse_lvl;
+       u32 micbias_pulse_time;
+       enum da7219_aad_btn_cfg btn_cfg;
+       enum da7219_aad_mic_det_thr mic_det_thr;
+       enum da7219_aad_jack_ins_deb jack_ins_deb;
+       enum da7219_aad_jack_det_rate jack_det_rate;
+       enum da7219_aad_jack_rem_deb jack_rem_deb;
+
+       u8 a_d_btn_thr;
+       u8 d_b_btn_thr;
+       u8 b_c_btn_thr;
+       u8 c_mic_btn_thr;
+
+       enum da7219_aad_btn_avg btn_avg;
+       enum da7219_aad_adc_1bit_rpt adc_1bit_rpt;
+};
+
+#endif /* __DA7219_AAD_PDATA_H */
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
new file mode 100644 (file)
index 0000000..3f39e13
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * da7219.h - DA7219 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_PDATA_H
+#define __DA7219_PDATA_H
+
+/* LDO */
+enum da7219_ldo_lvl_sel {
+       DA7219_LDO_LVL_SEL_1_05V = 0,
+       DA7219_LDO_LVL_SEL_1_10V,
+       DA7219_LDO_LVL_SEL_1_20V,
+       DA7219_LDO_LVL_SEL_1_40V,
+};
+
+/* Mic Bias */
+enum da7219_micbias_voltage {
+       DA7219_MICBIAS_1_8V = 1,
+       DA7219_MICBIAS_2_0V,
+       DA7219_MICBIAS_2_2V,
+       DA7219_MICBIAS_2_4V,
+       DA7219_MICBIAS_2_6V,
+};
+
+/* Mic input type */
+enum da7219_mic_amp_in_sel {
+       DA7219_MIC_AMP_IN_SEL_DIFF = 0,
+       DA7219_MIC_AMP_IN_SEL_SE_P,
+       DA7219_MIC_AMP_IN_SEL_SE_N,
+};
+
+struct da7219_aad_pdata;
+
+struct da7219_pdata {
+       /* Internal LDO */
+       enum da7219_ldo_lvl_sel ldo_lvl_sel;
+
+       /* Mic */
+       enum da7219_micbias_voltage micbias_lvl;
+       enum da7219_mic_amp_in_sel mic_amp_in_sel;
+
+       /* AAD */
+       struct da7219_aad_pdata *aad_pdata;
+};
+
+#endif /* __DA7219_PDATA_H */
index 3a8fca9409a7a0c1fad472155854b26f0a122487..8966ba7c962951de6fd1f972c092266a38b823d2 100644 (file)
@@ -38,6 +38,8 @@ struct i2s_clk_config_data {
 struct i2s_platform_data {
        #define DWC_I2S_PLAY    (1 << 0)
        #define DWC_I2S_RECORD  (1 << 1)
+       #define DW_I2S_SLAVE    (1 << 2)
+       #define DW_I2S_MASTER   (1 << 3)
        unsigned int cap;
        int channel;
        u32 snd_fmts;
index df705908480aebbf754900731834162fa8097f75..2767c55a641edd64b7018a0d7693826ae60dbad9 100644 (file)
@@ -67,7 +67,7 @@ int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
  * @reg: verb to write
  * @val: value to write
  *
- * For writing an amp value, use snd_hda_regmap_amp_update().
+ * For writing an amp value, use snd_hdac_regmap_update_amp().
  */
 static inline int
 snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
@@ -85,7 +85,7 @@ snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
  * @mask: bit mask to update
  * @val: value to update
  *
- * For updating an amp value, use snd_hda_regmap_amp_update().
+ * For updating an amp value, use snd_hdac_regmap_update_amp().
  */
 static inline int
 snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
index 49bc836fcd8483d522c48dc604fc3ba0d1bf153e..e2b712c90d3f22d4bcbb75ded3a296304d23d7c6 100644 (file)
@@ -21,22 +21,13 @@ struct hdac_stream;
 struct hdac_device;
 struct hdac_driver;
 struct hdac_widget_tree;
+struct hda_device_id;
 
 /*
  * exported bus type
  */
 extern struct bus_type snd_hda_bus_type;
 
-/*
- * HDA device table
- */
-struct hda_device_id {
-       __u32 vendor_id;
-       __u32 rev_id;
-       const char *name;
-       unsigned long driver_data;
-};
-
 /*
  * generic arrays
  */
@@ -117,6 +108,8 @@ int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
 void snd_hdac_device_exit(struct hdac_device *dev);
 int snd_hdac_device_register(struct hdac_device *codec);
 void snd_hdac_device_unregister(struct hdac_device *codec);
+int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name);
+int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size);
 
 int snd_hdac_refresh_widgets(struct hdac_device *codec);
 int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec);
@@ -147,6 +140,12 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
 bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
                                  unsigned int format);
 
+int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm);
+int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm);
+bool snd_hdac_check_power_state(struct hdac_device *hdac,
+               hda_nid_t nid, unsigned int target_state);
 /**
  * snd_hdac_read_parm - read a codec parameter
  * @codec: the codec object
index 94210dcdb6eacf5329fa8250f42a470a84d600ff..a4cadd9c297a810e1bb548d2cb02e4ab92b5eea2 100644 (file)
@@ -40,6 +40,13 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
 #define hbus_to_ebus(_bus) \
        container_of(_bus, struct hdac_ext_bus, bus)
 
+#define HDA_CODEC_REV_EXT_ENTRY(_vid, _rev, _name, drv_data) \
+       { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
+         .api_version = HDA_DEV_ASOC, \
+         .driver_data = (unsigned long)(drv_data) }
+#define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
+       HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)
+
 int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus);
 void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
index 691e7ee0a510ae6354ccb4d311823a687d47ee33..b0be09279943fc1a911a6071507ebdd79eed2912 100644 (file)
@@ -265,12 +265,12 @@ struct snd_ratden {
 
 struct snd_pcm_hw_constraint_ratnums {
        int nrats;
-       struct snd_ratnum *rats;
+       const struct snd_ratnum *rats;
 };
 
 struct snd_pcm_hw_constraint_ratdens {
        int nrats;
-       struct snd_ratden *rats;
+       const struct snd_ratden *rats;
 };
 
 struct snd_pcm_hw_constraint_list {
@@ -285,8 +285,6 @@ struct snd_pcm_hw_constraint_ranges {
        unsigned int mask;
 };
 
-struct snd_pcm_hwptr_log;
-
 /*
  * userspace-provided audio timestamp config to kernel,
  * structure is for internal use only and filled with dedicated unpack routine
@@ -404,10 +402,6 @@ struct snd_pcm_runtime {
        struct snd_pcm_hardware hw;
        struct snd_pcm_hw_constraints hw_constraints;
 
-       /* -- interrupt callbacks -- */
-       void (*transfer_ack_begin)(struct snd_pcm_substream *substream);
-       void (*transfer_ack_end)(struct snd_pcm_substream *substream);
-
        /* -- timer -- */
        unsigned int timer_resolution;  /* timer resolution */
        int tstamp_type;                /* timestamp type */
@@ -428,10 +422,6 @@ struct snd_pcm_runtime {
        /* -- OSS things -- */
        struct snd_pcm_oss_runtime oss;
 #endif
-
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       struct snd_pcm_hwptr_log *hwptr_log;
-#endif
 };
 
 struct snd_pcm_group {         /* keep linked substreams */
@@ -980,7 +970,7 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 int snd_interval_ranges(struct snd_interval *i, unsigned int count,
                        const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
-                       unsigned int rats_count, struct snd_ratnum *rats,
+                       unsigned int rats_count, const struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp);
 
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
@@ -1010,11 +1000,11 @@ int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratnums *r);
+                                 const struct snd_pcm_hw_constraint_ratnums *r);
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratdens *r);
+                                 const struct snd_pcm_hw_constraint_ratdens *r);
 int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
                                 unsigned int cond,
                                 unsigned int width,
@@ -1034,6 +1024,22 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime,
                        snd_pcm_hw_rule_func_t func, void *private,
                        int dep, ...);
 
+/**
+ * snd_pcm_hw_constraint_single() - Constrain parameter to a single value
+ * @runtime: PCM runtime instance
+ * @var: The hw_params variable to constrain
+ * @val: The value to constrain to
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+static inline int snd_pcm_hw_constraint_single(
+       struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
+       unsigned int val)
+{
+       return snd_pcm_hw_constraint_minmax(runtime, var, val, val);
+}
+
 int snd_pcm_format_signed(snd_pcm_format_t format);
 int snd_pcm_format_unsigned(snd_pcm_format_t format);
 int snd_pcm_format_linear(snd_pcm_format_t format);
@@ -1117,10 +1123,16 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
  *  Timer interface
  */
 
+#ifdef CONFIG_SND_PCM_TIMER
 void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
 void snd_pcm_timer_init(struct snd_pcm_substream *substream);
 void snd_pcm_timer_done(struct snd_pcm_substream *substream);
-
+#else
+static inline void
+snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
+#endif
 /**
  * snd_pcm_gettime - Fill the timespec depending on the timestamp mode
  * @runtime: PCM runtime instance
index 56e818e4a1cbf90270d21c3a67e44ff3a0f32d73..6ef629bde164c19ebb675e506fec7d98715d4956 100644 (file)
@@ -12,7 +12,6 @@ extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
 extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
 extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
-extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id);
 extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
 extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
 extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
deleted file mode 100644 (file)
index bb7b2eb..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef RCAR_SND_H
-#define RCAR_SND_H
-
-#include <linux/sh_clk.h>
-
-#define RSND_GEN1_SRU  0
-#define RSND_GEN1_ADG  1
-#define RSND_GEN1_SSI  2
-
-#define RSND_GEN2_SCU  0
-#define RSND_GEN2_ADG  1
-#define RSND_GEN2_SSIU 2
-#define RSND_GEN2_SSI  3
-
-#define RSND_BASE_MAX  4
-
-/*
- * flags
- *
- * 0xAB000000
- *
- * A : clock sharing settings
- * B : SSI direction
- */
-#define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
-#define RSND_SSI_NO_BUSIF              (1 << 30) /* SSI+DMA without BUSIF */
-
-#define RSND_SSI(_dma_id, _irq, _flags)                \
-{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
-#define RSND_SSI_UNUSED \
-{ .dma_id = -1, .irq = -1, .flags = 0 }
-
-struct rsnd_ssi_platform_info {
-       int dma_id;
-       int irq;
-       u32 flags;
-};
-
-#define RSND_SRC(rate, _dma_id)                                                \
-{ .convert_rate = rate, .dma_id = _dma_id, }
-#define RSND_SRC_UNUSED                                \
-{ .convert_rate = 0, .dma_id = -1, }
-
-struct rsnd_src_platform_info {
-       u32 convert_rate; /* sampling rate convert */
-       int dma_id; /* for Gen2 SCU */
-       int irq;
-};
-
-/*
- * flags
- */
-struct rsnd_ctu_platform_info {
-       u32 flags;
-};
-
-struct rsnd_mix_platform_info {
-       u32 flags;
-};
-
-struct rsnd_dvc_platform_info {
-       u32 flags;
-};
-
-struct rsnd_dai_path_info {
-       struct rsnd_ssi_platform_info *ssi;
-       struct rsnd_src_platform_info *src;
-       struct rsnd_ctu_platform_info *ctu;
-       struct rsnd_mix_platform_info *mix;
-       struct rsnd_dvc_platform_info *dvc;
-};
-
-struct rsnd_dai_platform_info {
-       struct rsnd_dai_path_info playback;
-       struct rsnd_dai_path_info capture;
-};
-
-/*
- * flags
- *
- * 0x0000000A
- *
- * A : generation
- */
-#define RSND_GEN_MASK  (0xF << 0)
-#define RSND_GEN1      (1 << 0) /* fixme */
-#define RSND_GEN2      (2 << 0) /* fixme */
-
-struct rcar_snd_info {
-       u32 flags;
-       struct rsnd_ssi_platform_info *ssi_info;
-       int ssi_info_nr;
-       struct rsnd_src_platform_info *src_info;
-       int src_info_nr;
-       struct rsnd_ctu_platform_info *ctu_info;
-       int ctu_info_nr;
-       struct rsnd_mix_platform_info *mix_info;
-       int mix_info_nr;
-       struct rsnd_dvc_platform_info *dvc_info;
-       int dvc_info_nr;
-       struct rsnd_dai_platform_info *dai_info;
-       int dai_info_nr;
-       int (*start)(int id);
-       int (*stop)(int id);
-};
-
-#endif
index 59d26dd81e45333e1730910a30493df4480059d5..e3c84b92ff70edd60d9b3c5204c9df80a991436d 100644 (file)
 #define __LINUX_SND_RT5640_H
 
 struct rt5640_platform_data {
-       /* IN1 & IN2 can optionally be differential */
+       /* IN1 & IN2 & IN3 can optionally be differential */
        bool in1_diff;
        bool in2_diff;
+       bool in3_diff;
 
        bool dmic_en;
        bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */
index 22734bc3ffd4a2e72ec1a1979ec1adf7df8014c6..a5cf6152e778929d572250462b2252a4369b08ca 100644 (file)
@@ -21,6 +21,8 @@ struct rt5645_platform_data {
        /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
 
        unsigned int jd_mode;
+       /* Invert JD when jack insert */
+       bool jd_invert;
 };
 
 #endif
index b9b4f289fe6b32130848cf4062ac94e4864f5bfb..0399352f3a6243569c87d3691fd664480749802c 100644 (file)
@@ -19,6 +19,8 @@ struct asoc_simple_dai {
        unsigned int sysclk;
        int slots;
        int slot_width;
+       unsigned int tx_slot_mask;
+       unsigned int rx_slot_mask;
        struct clk *clk;
 };
 
index 2df96b1384c718fdecc2a26d423a484dc5a9d727..212eaaf172ed49b8ac26d619ef3e0bce9553bee2 100644 (file)
@@ -48,10 +48,25 @@ struct snd_compr_stream;
 #define SND_SOC_DAIFMT_GATED           (0 << 4) /* clock is gated */
 
 /*
- * DAI hardware signal inversions.
+ * DAI hardware signal polarity.
  *
  * Specifies whether the DAI can also support inverted clocks for the specified
  * format.
+ *
+ * BCLK:
+ * - "normal" polarity means signal is available at rising edge of BCLK
+ * - "inverted" polarity means signal is available at falling edge of BCLK
+ *
+ * FSYNC "normal" polarity depends on the frame format:
+ * - I2S: frame consists of left then right channel data. Left channel starts
+ *      with falling FSYNC edge, right channel starts with rising FSYNC edge.
+ * - Left/Right Justified: frame consists of left then right channel data.
+ *      Left channel starts with rising FSYNC edge, right channel starts with
+ *      falling FSYNC edge.
+ * - DSP A/B: Frame starts with rising FSYNC edge.
+ * - AC97: Frame starts with rising FSYNC edge.
+ *
+ * "Negative" FSYNC polarity is the one opposite of "normal" polarity.
  */
 #define SND_SOC_DAIFMT_NB_NF           (0 << 8) /* normal bit clock + frame */
 #define SND_SOC_DAIFMT_NB_IF           (2 << 8) /* normal BCLK + inv FRM */
@@ -214,7 +229,7 @@ struct snd_soc_dai_driver {
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
        /* compress dai */
-       bool compress_dai;
+       int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
        /* DAI is also used for the control bus */
        bool bus_control;
 
index 5abba037d2456fc2616ae5df1270fd928299c1de..7855cfe46b69a044040f9ac5be92591e33af1799 100644 (file)
@@ -451,6 +451,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
        struct snd_kcontrol *kcontrol);
 
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
+               struct snd_kcontrol *kcontrol);
+
 int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
        enum snd_soc_bias_level level);
 
index 26ede14597daba32f8bf2cfcc84a821d094cc3d3..a8b4b9c8b1d2415e7220913715fc2cd4bd95212c 100644 (file)
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = \
                SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
+#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+        xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
+                                           xmax, xinvert) }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
+#define SOC_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \
+                                xhandler_get, xhandler_put, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_range, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .rreg = xreg, .shift = xshift, \
+                .rshift = xshift, .min = xmin, .max = xmax, \
+                .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -440,7 +459,9 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,
 int snd_soc_platform_write(struct snd_soc_platform *platform,
                                        unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
-int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
+#ifdef CONFIG_SND_SOC_COMPRESS
+int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
+#endif
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
                const char *dai_link, int stream);
@@ -593,7 +614,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
-int snd_soc_limit_volume(struct snd_soc_codec *codec,
+int snd_soc_limit_volume(struct snd_soc_card *card,
        const char *name, int max);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo);
@@ -1603,6 +1624,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                                          const char *propname);
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *tx_mask,
+                             unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width);
 void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
index 09b3880105a9e846e44a21e4f991018eaf64de0e..2d8639ea64d54dd7dd0f314281cfe1798a392250 100644 (file)
@@ -86,7 +86,7 @@
 #undef DECLARE_TRACE
 #define DECLARE_TRACE(name, proto, args)
 
-#ifdef CONFIG_EVENT_TRACING
+#ifdef TRACEPOINTS_ENABLED
 #include <trace/trace_events.h>
 #include <trace/perf.h>
 #endif
index 0b73af9be12f467d8b838c278297e30e273dbc49..b4473dab39d613e58e4d4e58e0049d72522047cd 100644 (file)
@@ -1117,6 +1117,119 @@ DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy,
        TP_ARGS(wq)
 );
 
+DECLARE_EVENT_CLASS(btrfs__qgroup_data_map,
+
+       TP_PROTO(struct inode *inode, u64 free_reserved),
+
+       TP_ARGS(inode, free_reserved),
+
+       TP_STRUCT__entry(
+               __field(        u64,            rootid          )
+               __field(        unsigned long,  ino             )
+               __field(        u64,            free_reserved   )
+       ),
+
+       TP_fast_assign(
+               __entry->rootid         =       BTRFS_I(inode)->root->objectid;
+               __entry->ino            =       inode->i_ino;
+               __entry->free_reserved  =       free_reserved;
+       ),
+
+       TP_printk("rootid=%llu, ino=%lu, free_reserved=%llu",
+                 __entry->rootid, __entry->ino, __entry->free_reserved)
+);
+
+DEFINE_EVENT(btrfs__qgroup_data_map, btrfs_qgroup_init_data_rsv_map,
+
+       TP_PROTO(struct inode *inode, u64 free_reserved),
+
+       TP_ARGS(inode, free_reserved)
+);
+
+DEFINE_EVENT(btrfs__qgroup_data_map, btrfs_qgroup_free_data_rsv_map,
+
+       TP_PROTO(struct inode *inode, u64 free_reserved),
+
+       TP_ARGS(inode, free_reserved)
+);
+
+#define BTRFS_QGROUP_OPERATIONS                                \
+       { QGROUP_RESERVE,       "reserve"       },      \
+       { QGROUP_RELEASE,       "release"       },      \
+       { QGROUP_FREE,          "free"          }
+
+DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
+
+       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+
+       TP_ARGS(inode, start, len, reserved, op),
+
+       TP_STRUCT__entry(
+               __field(        u64,            rootid          )
+               __field(        unsigned long,  ino             )
+               __field(        u64,            start           )
+               __field(        u64,            len             )
+               __field(        u64,            reserved        )
+               __field(        int,            op              )
+       ),
+
+       TP_fast_assign(
+               __entry->rootid         = BTRFS_I(inode)->root->objectid;
+               __entry->ino            = inode->i_ino;
+               __entry->start          = start;
+               __entry->len            = len;
+               __entry->reserved       = reserved;
+               __entry->op             = op;
+       ),
+
+       TP_printk("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s",
+                 __entry->rootid, __entry->ino, __entry->start, __entry->len,
+                 __entry->reserved,
+                 __print_flags((unsigned long)__entry->op, "",
+                               BTRFS_QGROUP_OPERATIONS)
+       )
+);
+
+DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_reserve_data,
+
+       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+
+       TP_ARGS(inode, start, len, reserved, op)
+);
+
+DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_release_data,
+
+       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+
+       TP_ARGS(inode, start, len, reserved, op)
+);
+
+DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref,
+
+       TP_PROTO(u64 ref_root, u64 reserved),
+
+       TP_ARGS(ref_root, reserved),
+
+       TP_STRUCT__entry(
+               __field(        u64,            ref_root        )
+               __field(        u64,            reserved        )
+       ),
+
+       TP_fast_assign(
+               __entry->ref_root       = ref_root;
+               __entry->reserved       = reserved;
+       ),
+
+       TP_printk("root=%llu, reserved=%llu, op=free",
+                 __entry->ref_root, __entry->reserved)
+);
+
+DEFINE_EVENT(btrfs__qgroup_delayed_ref, btrfs_qgroup_free_delayed_ref,
+
+       TP_PROTO(u64 ref_root, u64 reserved),
+
+       TP_ARGS(ref_root, reserved)
+);
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */
index 927a8ad9e51ba974b120e17b0fdc9a3716b5539a..2da73b92d47e9566f0d0148e966c398ab6bf8c40 100644 (file)
@@ -1,6 +1,10 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM gpio
 
+#ifndef CONFIG_TRACING_EVENTS_GPIO
+#define NOTRACE
+#endif
+
 #if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_GPIO_H
 
index 1b5443cebedcf4bf4bdaab60d856eaad33e87b74..26486fcd74ce4eb79039983c6a43572caa9f9f61 100644 (file)
@@ -1,261 +1,3 @@
-/*
- * Stage 4 of the trace events.
- *
- * Override the macros in <trace/trace_events.h> to include the following:
- *
- * For those macros defined with TRACE_EVENT:
- *
- * static struct trace_event_call event_<call>;
- *
- * static void trace_event_raw_event_<call>(void *__data, proto)
- * {
- *     struct trace_event_file *trace_file = __data;
- *     struct trace_event_call *event_call = trace_file->event_call;
- *     struct trace_event_data_offsets_<call> __maybe_unused __data_offsets;
- *     unsigned long eflags = trace_file->flags;
- *     enum event_trigger_type __tt = ETT_NONE;
- *     struct ring_buffer_event *event;
- *     struct trace_event_raw_<call> *entry; <-- defined in stage 1
- *     struct ring_buffer *buffer;
- *     unsigned long irq_flags;
- *     int __data_size;
- *     int pc;
- *
- *     if (!(eflags & EVENT_FILE_FL_TRIGGER_COND)) {
- *             if (eflags & EVENT_FILE_FL_TRIGGER_MODE)
- *                     event_triggers_call(trace_file, NULL);
- *             if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
- *                     return;
- *     }
- *
- *     local_save_flags(irq_flags);
- *     pc = preempt_count();
- *
- *     __data_size = trace_event_get_offsets_<call>(&__data_offsets, args);
- *
- *     event = trace_event_buffer_lock_reserve(&buffer, trace_file,
- *                               event_<call>->event.type,
- *                               sizeof(*entry) + __data_size,
- *                               irq_flags, pc);
- *     if (!event)
- *             return;
- *     entry   = ring_buffer_event_data(event);
- *
- *     { <assign>; }  <-- Here we assign the entries by the __field and
- *                        __array macros.
- *
- *     if (eflags & EVENT_FILE_FL_TRIGGER_COND)
- *             __tt = event_triggers_call(trace_file, entry);
- *
- *     if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT,
- *                  &trace_file->flags))
- *             ring_buffer_discard_commit(buffer, event);
- *     else if (!filter_check_discard(trace_file, entry, buffer, event))
- *             trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
- *
- *     if (__tt)
- *             event_triggers_post_call(trace_file, __tt);
- * }
- *
- * static struct trace_event ftrace_event_type_<call> = {
- *     .trace                  = trace_raw_output_<call>, <-- stage 2
- * };
- *
- * static char print_fmt_<call>[] = <TP_printk>;
- *
- * static struct trace_event_class __used event_class_<template> = {
- *     .system                 = "<system>",
- *     .define_fields          = trace_event_define_fields_<call>,
- *     .fields                 = LIST_HEAD_INIT(event_class_##call.fields),
- *     .raw_init               = trace_event_raw_init,
- *     .probe                  = trace_event_raw_event_##call,
- *     .reg                    = trace_event_reg,
- * };
- *
- * static struct trace_event_call event_<call> = {
- *     .class                  = event_class_<template>,
- *     {
- *             .tp                     = &__tracepoint_<call>,
- *     },
- *     .event                  = &ftrace_event_type_<call>,
- *     .print_fmt              = print_fmt_<call>,
- *     .flags                  = TRACE_EVENT_FL_TRACEPOINT,
- * };
- * // its only safe to use pointers when doing linker tricks to
- * // create an array.
- * static struct trace_event_call __used
- * __attribute__((section("_ftrace_events"))) *__event_<call> = &event_<call>;
- *
- */
-
-#ifdef CONFIG_PERF_EVENTS
-
-#define _TRACE_PERF_PROTO(call, proto)                                 \
-       static notrace void                                             \
-       perf_trace_##call(void *__data, proto);
-
-#define _TRACE_PERF_INIT(call)                                         \
-       .perf_probe             = perf_trace_##call,
-
-#else
-#define _TRACE_PERF_PROTO(call, proto)
-#define _TRACE_PERF_INIT(call)
-#endif /* CONFIG_PERF_EVENTS */
-
-#undef __entry
-#define __entry entry
-
-#undef __field
-#define __field(type, item)
-
-#undef __field_struct
-#define __field_struct(type, item)
-
-#undef __array
-#define __array(type, item, len)
-
-#undef __dynamic_array
-#define __dynamic_array(type, item, len)                               \
-       __entry->__data_loc_##item = __data_offsets.item;
-
-#undef __string
-#define __string(item, src) __dynamic_array(char, item, -1)
-
-#undef __assign_str
-#define __assign_str(dst, src)                                         \
-       strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)");
-
-#undef __bitmask
-#define __bitmask(item, nr_bits) __dynamic_array(unsigned long, item, -1)
-
-#undef __get_bitmask
-#define __get_bitmask(field) (char *)__get_dynamic_array(field)
-
-#undef __assign_bitmask
-#define __assign_bitmask(dst, src, nr_bits)                                    \
-       memcpy(__get_bitmask(dst), (src), __bitmask_size_in_bytes(nr_bits))
-
-#undef TP_fast_assign
-#define TP_fast_assign(args...) args
-
-#undef __perf_addr
-#define __perf_addr(a) (a)
-
-#undef __perf_count
-#define __perf_count(c)        (c)
-
-#undef __perf_task
-#define __perf_task(t) (t)
-
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
-                                                                       \
-static notrace void                                                    \
-trace_event_raw_event_##call(void *__data, proto)                      \
-{                                                                      \
-       struct trace_event_file *trace_file = __data;                   \
-       struct trace_event_data_offsets_##call __maybe_unused __data_offsets;\
-       struct trace_event_buffer fbuffer;                              \
-       struct trace_event_raw_##call *entry;                           \
-       int __data_size;                                                \
-                                                                       \
-       if (trace_trigger_soft_disabled(trace_file))                    \
-               return;                                                 \
-                                                                       \
-       __data_size = trace_event_get_offsets_##call(&__data_offsets, args); \
-                                                                       \
-       entry = trace_event_buffer_reserve(&fbuffer, trace_file,        \
-                                sizeof(*entry) + __data_size);         \
-                                                                       \
-       if (!entry)                                                     \
-               return;                                                 \
-                                                                       \
-       tstruct                                                         \
-                                                                       \
-       { assign; }                                                     \
-                                                                       \
-       trace_event_buffer_commit(&fbuffer);                            \
-}
-/*
- * The ftrace_test_probe is compiled out, it is only here as a build time check
- * to make sure that if the tracepoint handling changes, the ftrace probe will
- * fail to compile unless it too is updated.
- */
-
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, call, proto, args)                      \
-static inline void ftrace_test_probe_##call(void)                      \
-{                                                                      \
-       check_trace_callback_type_##call(trace_event_raw_event_##template); \
-}
-
-#undef DEFINE_EVENT_PRINT
-#define DEFINE_EVENT_PRINT(template, name, proto, args, print)
-
-#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
-
-#undef __entry
-#define __entry REC
-
-#undef __print_flags
-#undef __print_symbolic
-#undef __print_hex
-#undef __get_dynamic_array
-#undef __get_dynamic_array_len
-#undef __get_str
-#undef __get_bitmask
-#undef __print_array
-
-#undef TP_printk
-#define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
-
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
-_TRACE_PERF_PROTO(call, PARAMS(proto));                                        \
-static char print_fmt_##call[] = print;                                        \
-static struct trace_event_class __used __refdata event_class_##call = { \
-       .system                 = TRACE_SYSTEM_STRING,                  \
-       .define_fields          = trace_event_define_fields_##call,     \
-       .fields                 = LIST_HEAD_INIT(event_class_##call.fields),\
-       .raw_init               = trace_event_raw_init,                 \
-       .probe                  = trace_event_raw_event_##call,         \
-       .reg                    = trace_event_reg,                      \
-       _TRACE_PERF_INIT(call)                                          \
-};
-
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(template, call, proto, args)                      \
-                                                                       \
-static struct trace_event_call __used event_##call = {                 \
-       .class                  = &event_class_##template,              \
-       {                                                               \
-               .tp                     = &__tracepoint_##call,         \
-       },                                                              \
-       .event.funcs            = &trace_event_type_funcs_##template,   \
-       .print_fmt              = print_fmt_##template,                 \
-       .flags                  = TRACE_EVENT_FL_TRACEPOINT,            \
-};                                                                     \
-static struct trace_event_call __used                                  \
-__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
-
-#undef DEFINE_EVENT_PRINT
-#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
-                                                                       \
-static char print_fmt_##call[] = print;                                        \
-                                                                       \
-static struct trace_event_call __used event_##call = {                 \
-       .class                  = &event_class_##template,              \
-       {                                                               \
-               .tp                     = &__tracepoint_##call,         \
-       },                                                              \
-       .event.funcs            = &trace_event_type_funcs_##call,       \
-       .print_fmt              = print_fmt_##call,                     \
-       .flags                  = TRACE_EVENT_FL_TRACEPOINT,            \
-};                                                                     \
-static struct trace_event_call __used                                  \
-__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
-
-#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 #undef TRACE_SYSTEM_VAR
 
index 43be3b0e44d3e65e3543289b5251d2a53fe9593f..de996cf610536ee0da0657f2a4e9aae071793755 100644 (file)
@@ -506,3 +506,261 @@ static inline notrace int trace_event_get_offsets_##call(         \
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
+/*
+ * Stage 4 of the trace events.
+ *
+ * Override the macros in <trace/trace_events.h> to include the following:
+ *
+ * For those macros defined with TRACE_EVENT:
+ *
+ * static struct trace_event_call event_<call>;
+ *
+ * static void trace_event_raw_event_<call>(void *__data, proto)
+ * {
+ *     struct trace_event_file *trace_file = __data;
+ *     struct trace_event_call *event_call = trace_file->event_call;
+ *     struct trace_event_data_offsets_<call> __maybe_unused __data_offsets;
+ *     unsigned long eflags = trace_file->flags;
+ *     enum event_trigger_type __tt = ETT_NONE;
+ *     struct ring_buffer_event *event;
+ *     struct trace_event_raw_<call> *entry; <-- defined in stage 1
+ *     struct ring_buffer *buffer;
+ *     unsigned long irq_flags;
+ *     int __data_size;
+ *     int pc;
+ *
+ *     if (!(eflags & EVENT_FILE_FL_TRIGGER_COND)) {
+ *             if (eflags & EVENT_FILE_FL_TRIGGER_MODE)
+ *                     event_triggers_call(trace_file, NULL);
+ *             if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
+ *                     return;
+ *     }
+ *
+ *     local_save_flags(irq_flags);
+ *     pc = preempt_count();
+ *
+ *     __data_size = trace_event_get_offsets_<call>(&__data_offsets, args);
+ *
+ *     event = trace_event_buffer_lock_reserve(&buffer, trace_file,
+ *                               event_<call>->event.type,
+ *                               sizeof(*entry) + __data_size,
+ *                               irq_flags, pc);
+ *     if (!event)
+ *             return;
+ *     entry   = ring_buffer_event_data(event);
+ *
+ *     { <assign>; }  <-- Here we assign the entries by the __field and
+ *                        __array macros.
+ *
+ *     if (eflags & EVENT_FILE_FL_TRIGGER_COND)
+ *             __tt = event_triggers_call(trace_file, entry);
+ *
+ *     if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT,
+ *                  &trace_file->flags))
+ *             ring_buffer_discard_commit(buffer, event);
+ *     else if (!filter_check_discard(trace_file, entry, buffer, event))
+ *             trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+ *
+ *     if (__tt)
+ *             event_triggers_post_call(trace_file, __tt);
+ * }
+ *
+ * static struct trace_event ftrace_event_type_<call> = {
+ *     .trace                  = trace_raw_output_<call>, <-- stage 2
+ * };
+ *
+ * static char print_fmt_<call>[] = <TP_printk>;
+ *
+ * static struct trace_event_class __used event_class_<template> = {
+ *     .system                 = "<system>",
+ *     .define_fields          = trace_event_define_fields_<call>,
+ *     .fields                 = LIST_HEAD_INIT(event_class_##call.fields),
+ *     .raw_init               = trace_event_raw_init,
+ *     .probe                  = trace_event_raw_event_##call,
+ *     .reg                    = trace_event_reg,
+ * };
+ *
+ * static struct trace_event_call event_<call> = {
+ *     .class                  = event_class_<template>,
+ *     {
+ *             .tp                     = &__tracepoint_<call>,
+ *     },
+ *     .event                  = &ftrace_event_type_<call>,
+ *     .print_fmt              = print_fmt_<call>,
+ *     .flags                  = TRACE_EVENT_FL_TRACEPOINT,
+ * };
+ * // its only safe to use pointers when doing linker tricks to
+ * // create an array.
+ * static struct trace_event_call __used
+ * __attribute__((section("_ftrace_events"))) *__event_<call> = &event_<call>;
+ *
+ */
+
+#ifdef CONFIG_PERF_EVENTS
+
+#define _TRACE_PERF_PROTO(call, proto)                                 \
+       static notrace void                                             \
+       perf_trace_##call(void *__data, proto);
+
+#define _TRACE_PERF_INIT(call)                                         \
+       .perf_probe             = perf_trace_##call,
+
+#else
+#define _TRACE_PERF_PROTO(call, proto)
+#define _TRACE_PERF_INIT(call)
+#endif /* CONFIG_PERF_EVENTS */
+
+#undef __entry
+#define __entry entry
+
+#undef __field
+#define __field(type, item)
+
+#undef __field_struct
+#define __field_struct(type, item)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                               \
+       __entry->__data_loc_##item = __data_offsets.item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef __assign_str
+#define __assign_str(dst, src)                                         \
+       strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)");
+
+#undef __bitmask
+#define __bitmask(item, nr_bits) __dynamic_array(unsigned long, item, -1)
+
+#undef __get_bitmask
+#define __get_bitmask(field) (char *)__get_dynamic_array(field)
+
+#undef __assign_bitmask
+#define __assign_bitmask(dst, src, nr_bits)                                    \
+       memcpy(__get_bitmask(dst), (src), __bitmask_size_in_bytes(nr_bits))
+
+#undef TP_fast_assign
+#define TP_fast_assign(args...) args
+
+#undef __perf_addr
+#define __perf_addr(a) (a)
+
+#undef __perf_count
+#define __perf_count(c)        (c)
+
+#undef __perf_task
+#define __perf_task(t) (t)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+                                                                       \
+static notrace void                                                    \
+trace_event_raw_event_##call(void *__data, proto)                      \
+{                                                                      \
+       struct trace_event_file *trace_file = __data;                   \
+       struct trace_event_data_offsets_##call __maybe_unused __data_offsets;\
+       struct trace_event_buffer fbuffer;                              \
+       struct trace_event_raw_##call *entry;                           \
+       int __data_size;                                                \
+                                                                       \
+       if (trace_trigger_soft_disabled(trace_file))                    \
+               return;                                                 \
+                                                                       \
+       __data_size = trace_event_get_offsets_##call(&__data_offsets, args); \
+                                                                       \
+       entry = trace_event_buffer_reserve(&fbuffer, trace_file,        \
+                                sizeof(*entry) + __data_size);         \
+                                                                       \
+       if (!entry)                                                     \
+               return;                                                 \
+                                                                       \
+       tstruct                                                         \
+                                                                       \
+       { assign; }                                                     \
+                                                                       \
+       trace_event_buffer_commit(&fbuffer);                            \
+}
+/*
+ * The ftrace_test_probe is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the ftrace probe will
+ * fail to compile unless it too is updated.
+ */
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+static inline void ftrace_test_probe_##call(void)                      \
+{                                                                      \
+       check_trace_callback_type_##call(trace_event_raw_event_##template); \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print)
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef __entry
+#define __entry REC
+
+#undef __print_flags
+#undef __print_symbolic
+#undef __print_hex
+#undef __get_dynamic_array
+#undef __get_dynamic_array_len
+#undef __get_str
+#undef __get_bitmask
+#undef __print_array
+
+#undef TP_printk
+#define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+_TRACE_PERF_PROTO(call, PARAMS(proto));                                        \
+static char print_fmt_##call[] = print;                                        \
+static struct trace_event_class __used __refdata event_class_##call = { \
+       .system                 = TRACE_SYSTEM_STRING,                  \
+       .define_fields          = trace_event_define_fields_##call,     \
+       .fields                 = LIST_HEAD_INIT(event_class_##call.fields),\
+       .raw_init               = trace_event_raw_init,                 \
+       .probe                  = trace_event_raw_event_##call,         \
+       .reg                    = trace_event_reg,                      \
+       _TRACE_PERF_INIT(call)                                          \
+};
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+                                                                       \
+static struct trace_event_call __used event_##call = {                 \
+       .class                  = &event_class_##template,              \
+       {                                                               \
+               .tp                     = &__tracepoint_##call,         \
+       },                                                              \
+       .event.funcs            = &trace_event_type_funcs_##template,   \
+       .print_fmt              = print_fmt_##template,                 \
+       .flags                  = TRACE_EVENT_FL_TRACEPOINT,            \
+};                                                                     \
+static struct trace_event_call __used                                  \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
+                                                                       \
+static char print_fmt_##call[] = print;                                        \
+                                                                       \
+static struct trace_event_call __used event_##call = {                 \
+       .class                  = &event_class_##template,              \
+       {                                                               \
+               .tp                     = &__tracepoint_##call,         \
+       },                                                              \
+       .event.funcs            = &trace_event_type_funcs_##call,       \
+       .print_fmt              = print_fmt_##call,                     \
+       .flags                  = TRACE_EVENT_FL_TRACEPOINT,            \
+};                                                                     \
+static struct trace_event_call __used                                  \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
index 70d89230b6416c6e59858d6936695adf71770e85..628e6e64c2fb4ff2c858a57e0beeca3aa4fd49b6 100644 (file)
@@ -191,6 +191,7 @@ header-y += inet_diag.h
 header-y += in.h
 header-y += inotify.h
 header-y += input.h
+header-y += input-event-codes.h
 header-y += in_route.h
 header-y += ioctl.h
 header-y += ip6_tunnel.h
index a8519446c111ab02fb71e79e6b31fea1df666223..63739a035085f9746389853a74839b4ad85aaf1a 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _LINUX_BLKPG_H
-#define _LINUX_BLKPG_H
+#ifndef _UAPI__LINUX_BLKPG_H
+#define _UAPI__LINUX_BLKPG_H
 
 /*
  * Partition table and disk geometry handling
@@ -56,4 +56,4 @@ struct blkpg_partition {
        char volname[BLKPG_VOLNAMELTH]; /* volume label */
 };
 
-#endif /* _LINUX_BLKPG_H */
+#endif /* _UAPI__LINUX_BLKPG_H */
index b6dec05c7196a22511e346242724406eef88265b..dea8931992571a6e87569024567af5aff6cef01b 100644 (file)
@@ -206,7 +206,13 @@ struct btrfs_ioctl_feature_flags {
  */
 struct btrfs_balance_args {
        __u64 profiles;
-       __u64 usage;
+       union {
+               __le64 usage;
+               struct {
+                       __le32 usage_min;
+                       __le32 usage_max;
+               };
+       };
        __u64 devid;
        __u64 pstart;
        __u64 pend;
@@ -217,8 +223,27 @@ struct btrfs_balance_args {
 
        __u64 flags;
 
-       __u64 limit;            /* limit number of processed chunks */
-       __u64 unused[7];
+       /*
+        * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+        * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
+        * and maximum
+        */
+       union {
+               __u64 limit;            /* limit number of processed chunks */
+               struct {
+                       __u32 limit_min;
+                       __u32 limit_max;
+               };
+       };
+
+       /*
+        * Process chunks that cross stripes_min..stripes_max devices,
+        * BTRFS_BALANCE_ARGS_STRIPES_RANGE
+        */
+       __le32 stripes_min;
+       __le32 stripes_max;
+
+       __u64 unused[6];
 } __attribute__ ((__packed__));
 
 /* report balance progress to userspace */
index 9b964a5920afbaca68d2e3976e883b4fba54f4ba..f15d980249b502e4638e6125f04e595f0f52035e 100644 (file)
@@ -197,6 +197,7 @@ struct inodes_stat_t {
 #define FS_EXTENT_FL                   0x00080000 /* Extents */
 #define FS_DIRECTIO_FL                 0x00100000 /* Use direct i/o */
 #define FS_NOCOW_FL                    0x00800000 /* Do not cow file */
+#define FS_PROJINHERIT_FL              0x20000000 /* Create with parents projid */
 #define FS_RESERVED_FL                 0x80000000 /* reserved for ext2 lib */
 
 #define FS_FL_USER_VISIBLE             0x0003DFFF /* User visible flags */
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
new file mode 100644 (file)
index 0000000..87cf351
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * Input event codes
+ *
+ *    *** IMPORTANT ***
+ * This file is not only included from C-code but also from devicetree source
+ * files. As such this file MUST only contain comments and defines.
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2015 Hans de Goede <hdegoede@redhat.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 _UAPI_INPUT_EVENT_CODES_H
+#define _UAPI_INPUT_EVENT_CODES_H
+
+/*
+ * Device properties and quirks
+ */
+
+#define INPUT_PROP_POINTER             0x00    /* needs a pointer */
+#define INPUT_PROP_DIRECT              0x01    /* direct input devices */
+#define INPUT_PROP_BUTTONPAD           0x02    /* has button(s) under pad */
+#define INPUT_PROP_SEMI_MT             0x03    /* touch rectangle only */
+#define INPUT_PROP_TOPBUTTONPAD                0x04    /* softbuttons at top of pad */
+#define INPUT_PROP_POINTING_STICK      0x05    /* is a pointing stick */
+#define INPUT_PROP_ACCELEROMETER       0x06    /* has accelerometer */
+
+#define INPUT_PROP_MAX                 0x1f
+#define INPUT_PROP_CNT                 (INPUT_PROP_MAX + 1)
+
+/*
+ * Event types
+ */
+
+#define EV_SYN                 0x00
+#define EV_KEY                 0x01
+#define EV_REL                 0x02
+#define EV_ABS                 0x03
+#define EV_MSC                 0x04
+#define EV_SW                  0x05
+#define EV_LED                 0x11
+#define EV_SND                 0x12
+#define EV_REP                 0x14
+#define EV_FF                  0x15
+#define EV_PWR                 0x16
+#define EV_FF_STATUS           0x17
+#define EV_MAX                 0x1f
+#define EV_CNT                 (EV_MAX+1)
+
+/*
+ * Synchronization events.
+ */
+
+#define SYN_REPORT             0
+#define SYN_CONFIG             1
+#define SYN_MT_REPORT          2
+#define SYN_DROPPED            3
+#define SYN_MAX                        0xf
+#define SYN_CNT                        (SYN_MAX+1)
+
+/*
+ * Keys and buttons
+ *
+ * Most of the keys/buttons are modeled after USB HUT 1.12
+ * (see http://www.usb.org/developers/hidpage).
+ * Abbreviations in the comments:
+ * AC - Application Control
+ * AL - Application Launch Button
+ * SC - System Control
+ */
+
+#define KEY_RESERVED           0
+#define KEY_ESC                        1
+#define KEY_1                  2
+#define KEY_2                  3
+#define KEY_3                  4
+#define KEY_4                  5
+#define KEY_5                  6
+#define KEY_6                  7
+#define KEY_7                  8
+#define KEY_8                  9
+#define KEY_9                  10
+#define KEY_0                  11
+#define KEY_MINUS              12
+#define KEY_EQUAL              13
+#define KEY_BACKSPACE          14
+#define KEY_TAB                        15
+#define KEY_Q                  16
+#define KEY_W                  17
+#define KEY_E                  18
+#define KEY_R                  19
+#define KEY_T                  20
+#define KEY_Y                  21
+#define KEY_U                  22
+#define KEY_I                  23
+#define KEY_O                  24
+#define KEY_P                  25
+#define KEY_LEFTBRACE          26
+#define KEY_RIGHTBRACE         27
+#define KEY_ENTER              28
+#define KEY_LEFTCTRL           29
+#define KEY_A                  30
+#define KEY_S                  31
+#define KEY_D                  32
+#define KEY_F                  33
+#define KEY_G                  34
+#define KEY_H                  35
+#define KEY_J                  36
+#define KEY_K                  37
+#define KEY_L                  38
+#define KEY_SEMICOLON          39
+#define KEY_APOSTROPHE         40
+#define KEY_GRAVE              41
+#define KEY_LEFTSHIFT          42
+#define KEY_BACKSLASH          43
+#define KEY_Z                  44
+#define KEY_X                  45
+#define KEY_C                  46
+#define KEY_V                  47
+#define KEY_B                  48
+#define KEY_N                  49
+#define KEY_M                  50
+#define KEY_COMMA              51
+#define KEY_DOT                        52
+#define KEY_SLASH              53
+#define KEY_RIGHTSHIFT         54
+#define KEY_KPASTERISK         55
+#define KEY_LEFTALT            56
+#define KEY_SPACE              57
+#define KEY_CAPSLOCK           58
+#define KEY_F1                 59
+#define KEY_F2                 60
+#define KEY_F3                 61
+#define KEY_F4                 62
+#define KEY_F5                 63
+#define KEY_F6                 64
+#define KEY_F7                 65
+#define KEY_F8                 66
+#define KEY_F9                 67
+#define KEY_F10                        68
+#define KEY_NUMLOCK            69
+#define KEY_SCROLLLOCK         70
+#define KEY_KP7                        71
+#define KEY_KP8                        72
+#define KEY_KP9                        73
+#define KEY_KPMINUS            74
+#define KEY_KP4                        75
+#define KEY_KP5                        76
+#define KEY_KP6                        77
+#define KEY_KPPLUS             78
+#define KEY_KP1                        79
+#define KEY_KP2                        80
+#define KEY_KP3                        81
+#define KEY_KP0                        82
+#define KEY_KPDOT              83
+
+#define KEY_ZENKAKUHANKAKU     85
+#define KEY_102ND              86
+#define KEY_F11                        87
+#define KEY_F12                        88
+#define KEY_RO                 89
+#define KEY_KATAKANA           90
+#define KEY_HIRAGANA           91
+#define KEY_HENKAN             92
+#define KEY_KATAKANAHIRAGANA   93
+#define KEY_MUHENKAN           94
+#define KEY_KPJPCOMMA          95
+#define KEY_KPENTER            96
+#define KEY_RIGHTCTRL          97
+#define KEY_KPSLASH            98
+#define KEY_SYSRQ              99
+#define KEY_RIGHTALT           100
+#define KEY_LINEFEED           101
+#define KEY_HOME               102
+#define KEY_UP                 103
+#define KEY_PAGEUP             104
+#define KEY_LEFT               105
+#define KEY_RIGHT              106
+#define KEY_END                        107
+#define KEY_DOWN               108
+#define KEY_PAGEDOWN           109
+#define KEY_INSERT             110
+#define KEY_DELETE             111
+#define KEY_MACRO              112
+#define KEY_MUTE               113
+#define KEY_VOLUMEDOWN         114
+#define KEY_VOLUMEUP           115
+#define KEY_POWER              116     /* SC System Power Down */
+#define KEY_KPEQUAL            117
+#define KEY_KPPLUSMINUS                118
+#define KEY_PAUSE              119
+#define KEY_SCALE              120     /* AL Compiz Scale (Expose) */
+
+#define KEY_KPCOMMA            121
+#define KEY_HANGEUL            122
+#define KEY_HANGUEL            KEY_HANGEUL
+#define KEY_HANJA              123
+#define KEY_YEN                        124
+#define KEY_LEFTMETA           125
+#define KEY_RIGHTMETA          126
+#define KEY_COMPOSE            127
+
+#define KEY_STOP               128     /* AC Stop */
+#define KEY_AGAIN              129
+#define KEY_PROPS              130     /* AC Properties */
+#define KEY_UNDO               131     /* AC Undo */
+#define KEY_FRONT              132
+#define KEY_COPY               133     /* AC Copy */
+#define KEY_OPEN               134     /* AC Open */
+#define KEY_PASTE              135     /* AC Paste */
+#define KEY_FIND               136     /* AC Search */
+#define KEY_CUT                        137     /* AC Cut */
+#define KEY_HELP               138     /* AL Integrated Help Center */
+#define KEY_MENU               139     /* Menu (show menu) */
+#define KEY_CALC               140     /* AL Calculator */
+#define KEY_SETUP              141
+#define KEY_SLEEP              142     /* SC System Sleep */
+#define KEY_WAKEUP             143     /* System Wake Up */
+#define KEY_FILE               144     /* AL Local Machine Browser */
+#define KEY_SENDFILE           145
+#define KEY_DELETEFILE         146
+#define KEY_XFER               147
+#define KEY_PROG1              148
+#define KEY_PROG2              149
+#define KEY_WWW                        150     /* AL Internet Browser */
+#define KEY_MSDOS              151
+#define KEY_COFFEE             152     /* AL Terminal Lock/Screensaver */
+#define KEY_SCREENLOCK         KEY_COFFEE
+#define KEY_ROTATE_DISPLAY     153     /* Display orientation for e.g. tablets */
+#define KEY_DIRECTION          KEY_ROTATE_DISPLAY
+#define KEY_CYCLEWINDOWS       154
+#define KEY_MAIL               155
+#define KEY_BOOKMARKS          156     /* AC Bookmarks */
+#define KEY_COMPUTER           157
+#define KEY_BACK               158     /* AC Back */
+#define KEY_FORWARD            159     /* AC Forward */
+#define KEY_CLOSECD            160
+#define KEY_EJECTCD            161
+#define KEY_EJECTCLOSECD       162
+#define KEY_NEXTSONG           163
+#define KEY_PLAYPAUSE          164
+#define KEY_PREVIOUSSONG       165
+#define KEY_STOPCD             166
+#define KEY_RECORD             167
+#define KEY_REWIND             168
+#define KEY_PHONE              169     /* Media Select Telephone */
+#define KEY_ISO                        170
+#define KEY_CONFIG             171     /* AL Consumer Control Configuration */
+#define KEY_HOMEPAGE           172     /* AC Home */
+#define KEY_REFRESH            173     /* AC Refresh */
+#define KEY_EXIT               174     /* AC Exit */
+#define KEY_MOVE               175
+#define KEY_EDIT               176
+#define KEY_SCROLLUP           177
+#define KEY_SCROLLDOWN         178
+#define KEY_KPLEFTPAREN                179
+#define KEY_KPRIGHTPAREN       180
+#define KEY_NEW                        181     /* AC New */
+#define KEY_REDO               182     /* AC Redo/Repeat */
+
+#define KEY_F13                        183
+#define KEY_F14                        184
+#define KEY_F15                        185
+#define KEY_F16                        186
+#define KEY_F17                        187
+#define KEY_F18                        188
+#define KEY_F19                        189
+#define KEY_F20                        190
+#define KEY_F21                        191
+#define KEY_F22                        192
+#define KEY_F23                        193
+#define KEY_F24                        194
+
+#define KEY_PLAYCD             200
+#define KEY_PAUSECD            201
+#define KEY_PROG3              202
+#define KEY_PROG4              203
+#define KEY_DASHBOARD          204     /* AL Dashboard */
+#define KEY_SUSPEND            205
+#define KEY_CLOSE              206     /* AC Close */
+#define KEY_PLAY               207
+#define KEY_FASTFORWARD                208
+#define KEY_BASSBOOST          209
+#define KEY_PRINT              210     /* AC Print */
+#define KEY_HP                 211
+#define KEY_CAMERA             212
+#define KEY_SOUND              213
+#define KEY_QUESTION           214
+#define KEY_EMAIL              215
+#define KEY_CHAT               216
+#define KEY_SEARCH             217
+#define KEY_CONNECT            218
+#define KEY_FINANCE            219     /* AL Checkbook/Finance */
+#define KEY_SPORT              220
+#define KEY_SHOP               221
+#define KEY_ALTERASE           222
+#define KEY_CANCEL             223     /* AC Cancel */
+#define KEY_BRIGHTNESSDOWN     224
+#define KEY_BRIGHTNESSUP       225
+#define KEY_MEDIA              226
+
+#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
+                                          outputs (Monitor/LCD/TV-out/etc) */
+#define KEY_KBDILLUMTOGGLE     228
+#define KEY_KBDILLUMDOWN       229
+#define KEY_KBDILLUMUP         230
+
+#define KEY_SEND               231     /* AC Send */
+#define KEY_REPLY              232     /* AC Reply */
+#define KEY_FORWARDMAIL                233     /* AC Forward Msg */
+#define KEY_SAVE               234     /* AC Save */
+#define KEY_DOCUMENTS          235
+
+#define KEY_BATTERY            236
+
+#define KEY_BLUETOOTH          237
+#define KEY_WLAN               238
+#define KEY_UWB                        239
+
+#define KEY_UNKNOWN            240
+
+#define KEY_VIDEO_NEXT         241     /* drive next video source */
+#define KEY_VIDEO_PREV         242     /* drive previous video source */
+#define KEY_BRIGHTNESS_CYCLE   243     /* brightness up, after max is min */
+#define KEY_BRIGHTNESS_AUTO    244     /* Set Auto Brightness: manual
+                                         brightness control is off,
+                                         rely on ambient */
+#define KEY_BRIGHTNESS_ZERO    KEY_BRIGHTNESS_AUTO
+#define KEY_DISPLAY_OFF                245     /* display device to off state */
+
+#define KEY_WWAN               246     /* Wireless WAN (LTE, UMTS, GSM, etc.) */
+#define KEY_WIMAX              KEY_WWAN
+#define KEY_RFKILL             247     /* Key that controls all radios */
+
+#define KEY_MICMUTE            248     /* Mute / unmute the microphone */
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+
+#define BTN_MISC               0x100
+#define BTN_0                  0x100
+#define BTN_1                  0x101
+#define BTN_2                  0x102
+#define BTN_3                  0x103
+#define BTN_4                  0x104
+#define BTN_5                  0x105
+#define BTN_6                  0x106
+#define BTN_7                  0x107
+#define BTN_8                  0x108
+#define BTN_9                  0x109
+
+#define BTN_MOUSE              0x110
+#define BTN_LEFT               0x110
+#define BTN_RIGHT              0x111
+#define BTN_MIDDLE             0x112
+#define BTN_SIDE               0x113
+#define BTN_EXTRA              0x114
+#define BTN_FORWARD            0x115
+#define BTN_BACK               0x116
+#define BTN_TASK               0x117
+
+#define BTN_JOYSTICK           0x120
+#define BTN_TRIGGER            0x120
+#define BTN_THUMB              0x121
+#define BTN_THUMB2             0x122
+#define BTN_TOP                        0x123
+#define BTN_TOP2               0x124
+#define BTN_PINKIE             0x125
+#define BTN_BASE               0x126
+#define BTN_BASE2              0x127
+#define BTN_BASE3              0x128
+#define BTN_BASE4              0x129
+#define BTN_BASE5              0x12a
+#define BTN_BASE6              0x12b
+#define BTN_DEAD               0x12f
+
+#define BTN_GAMEPAD            0x130
+#define BTN_SOUTH              0x130
+#define BTN_A                  BTN_SOUTH
+#define BTN_EAST               0x131
+#define BTN_B                  BTN_EAST
+#define BTN_C                  0x132
+#define BTN_NORTH              0x133
+#define BTN_X                  BTN_NORTH
+#define BTN_WEST               0x134
+#define BTN_Y                  BTN_WEST
+#define BTN_Z                  0x135
+#define BTN_TL                 0x136
+#define BTN_TR                 0x137
+#define BTN_TL2                        0x138
+#define BTN_TR2                        0x139
+#define BTN_SELECT             0x13a
+#define BTN_START              0x13b
+#define BTN_MODE               0x13c
+#define BTN_THUMBL             0x13d
+#define BTN_THUMBR             0x13e
+
+#define BTN_DIGI               0x140
+#define BTN_TOOL_PEN           0x140
+#define BTN_TOOL_RUBBER                0x141
+#define BTN_TOOL_BRUSH         0x142
+#define BTN_TOOL_PENCIL                0x143
+#define BTN_TOOL_AIRBRUSH      0x144
+#define BTN_TOOL_FINGER                0x145
+#define BTN_TOOL_MOUSE         0x146
+#define BTN_TOOL_LENS          0x147
+#define BTN_TOOL_QUINTTAP      0x148   /* Five fingers on trackpad */
+#define BTN_TOUCH              0x14a
+#define BTN_STYLUS             0x14b
+#define BTN_STYLUS2            0x14c
+#define BTN_TOOL_DOUBLETAP     0x14d
+#define BTN_TOOL_TRIPLETAP     0x14e
+#define BTN_TOOL_QUADTAP       0x14f   /* Four fingers on trackpad */
+
+#define BTN_WHEEL              0x150
+#define BTN_GEAR_DOWN          0x150
+#define BTN_GEAR_UP            0x151
+
+#define KEY_OK                 0x160
+#define KEY_SELECT             0x161
+#define KEY_GOTO               0x162
+#define KEY_CLEAR              0x163
+#define KEY_POWER2             0x164
+#define KEY_OPTION             0x165
+#define KEY_INFO               0x166   /* AL OEM Features/Tips/Tutorial */
+#define KEY_TIME               0x167
+#define KEY_VENDOR             0x168
+#define KEY_ARCHIVE            0x169
+#define KEY_PROGRAM            0x16a   /* Media Select Program Guide */
+#define KEY_CHANNEL            0x16b
+#define KEY_FAVORITES          0x16c
+#define KEY_EPG                        0x16d
+#define KEY_PVR                        0x16e   /* Media Select Home */
+#define KEY_MHP                        0x16f
+#define KEY_LANGUAGE           0x170
+#define KEY_TITLE              0x171
+#define KEY_SUBTITLE           0x172
+#define KEY_ANGLE              0x173
+#define KEY_ZOOM               0x174
+#define KEY_MODE               0x175
+#define KEY_KEYBOARD           0x176
+#define KEY_SCREEN             0x177
+#define KEY_PC                 0x178   /* Media Select Computer */
+#define KEY_TV                 0x179   /* Media Select TV */
+#define KEY_TV2                        0x17a   /* Media Select Cable */
+#define KEY_VCR                        0x17b   /* Media Select VCR */
+#define KEY_VCR2               0x17c   /* VCR Plus */
+#define KEY_SAT                        0x17d   /* Media Select Satellite */
+#define KEY_SAT2               0x17e
+#define KEY_CD                 0x17f   /* Media Select CD */
+#define KEY_TAPE               0x180   /* Media Select Tape */
+#define KEY_RADIO              0x181
+#define KEY_TUNER              0x182   /* Media Select Tuner */
+#define KEY_PLAYER             0x183
+#define KEY_TEXT               0x184
+#define KEY_DVD                        0x185   /* Media Select DVD */
+#define KEY_AUX                        0x186
+#define KEY_MP3                        0x187
+#define KEY_AUDIO              0x188   /* AL Audio Browser */
+#define KEY_VIDEO              0x189   /* AL Movie Browser */
+#define KEY_DIRECTORY          0x18a
+#define KEY_LIST               0x18b
+#define KEY_MEMO               0x18c   /* Media Select Messages */
+#define KEY_CALENDAR           0x18d
+#define KEY_RED                        0x18e
+#define KEY_GREEN              0x18f
+#define KEY_YELLOW             0x190
+#define KEY_BLUE               0x191
+#define KEY_CHANNELUP          0x192   /* Channel Increment */
+#define KEY_CHANNELDOWN                0x193   /* Channel Decrement */
+#define KEY_FIRST              0x194
+#define KEY_LAST               0x195   /* Recall Last */
+#define KEY_AB                 0x196
+#define KEY_NEXT               0x197
+#define KEY_RESTART            0x198
+#define KEY_SLOW               0x199
+#define KEY_SHUFFLE            0x19a
+#define KEY_BREAK              0x19b
+#define KEY_PREVIOUS           0x19c
+#define KEY_DIGITS             0x19d
+#define KEY_TEEN               0x19e
+#define KEY_TWEN               0x19f
+#define KEY_VIDEOPHONE         0x1a0   /* Media Select Video Phone */
+#define KEY_GAMES              0x1a1   /* Media Select Games */
+#define KEY_ZOOMIN             0x1a2   /* AC Zoom In */
+#define KEY_ZOOMOUT            0x1a3   /* AC Zoom Out */
+#define KEY_ZOOMRESET          0x1a4   /* AC Zoom */
+#define KEY_WORDPROCESSOR      0x1a5   /* AL Word Processor */
+#define KEY_EDITOR             0x1a6   /* AL Text Editor */
+#define KEY_SPREADSHEET                0x1a7   /* AL Spreadsheet */
+#define KEY_GRAPHICSEDITOR     0x1a8   /* AL Graphics Editor */
+#define KEY_PRESENTATION       0x1a9   /* AL Presentation App */
+#define KEY_DATABASE           0x1aa   /* AL Database App */
+#define KEY_NEWS               0x1ab   /* AL Newsreader */
+#define KEY_VOICEMAIL          0x1ac   /* AL Voicemail */
+#define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
+#define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
+#define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
+#define KEY_BRIGHTNESS_TOGGLE  KEY_DISPLAYTOGGLE
+#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
+#define KEY_LOGOFF             0x1b1   /* AL Logoff */
+
+#define KEY_DOLLAR             0x1b2
+#define KEY_EURO               0x1b3
+
+#define KEY_FRAMEBACK          0x1b4   /* Consumer - transport controls */
+#define KEY_FRAMEFORWARD       0x1b5
+#define KEY_CONTEXT_MENU       0x1b6   /* GenDesc - system context menu */
+#define KEY_MEDIA_REPEAT       0x1b7   /* Consumer - transport control */
+#define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
+#define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
+#define KEY_IMAGES             0x1ba   /* AL Image Browser */
+
+#define KEY_DEL_EOL            0x1c0
+#define KEY_DEL_EOS            0x1c1
+#define KEY_INS_LINE           0x1c2
+#define KEY_DEL_LINE           0x1c3
+
+#define KEY_FN                 0x1d0
+#define KEY_FN_ESC             0x1d1
+#define KEY_FN_F1              0x1d2
+#define KEY_FN_F2              0x1d3
+#define KEY_FN_F3              0x1d4
+#define KEY_FN_F4              0x1d5
+#define KEY_FN_F5              0x1d6
+#define KEY_FN_F6              0x1d7
+#define KEY_FN_F7              0x1d8
+#define KEY_FN_F8              0x1d9
+#define KEY_FN_F9              0x1da
+#define KEY_FN_F10             0x1db
+#define KEY_FN_F11             0x1dc
+#define KEY_FN_F12             0x1dd
+#define KEY_FN_1               0x1de
+#define KEY_FN_2               0x1df
+#define KEY_FN_D               0x1e0
+#define KEY_FN_E               0x1e1
+#define KEY_FN_F               0x1e2
+#define KEY_FN_S               0x1e3
+#define KEY_FN_B               0x1e4
+
+#define KEY_BRL_DOT1           0x1f1
+#define KEY_BRL_DOT2           0x1f2
+#define KEY_BRL_DOT3           0x1f3
+#define KEY_BRL_DOT4           0x1f4
+#define KEY_BRL_DOT5           0x1f5
+#define KEY_BRL_DOT6           0x1f6
+#define KEY_BRL_DOT7           0x1f7
+#define KEY_BRL_DOT8           0x1f8
+#define KEY_BRL_DOT9           0x1f9
+#define KEY_BRL_DOT10          0x1fa
+
+#define KEY_NUMERIC_0          0x200   /* used by phones, remote controls, */
+#define KEY_NUMERIC_1          0x201   /* and other keypads */
+#define KEY_NUMERIC_2          0x202
+#define KEY_NUMERIC_3          0x203
+#define KEY_NUMERIC_4          0x204
+#define KEY_NUMERIC_5          0x205
+#define KEY_NUMERIC_6          0x206
+#define KEY_NUMERIC_7          0x207
+#define KEY_NUMERIC_8          0x208
+#define KEY_NUMERIC_9          0x209
+#define KEY_NUMERIC_STAR       0x20a
+#define KEY_NUMERIC_POUND      0x20b
+#define KEY_NUMERIC_A          0x20c   /* Phone key A - HUT Telephony 0xb9 */
+#define KEY_NUMERIC_B          0x20d
+#define KEY_NUMERIC_C          0x20e
+#define KEY_NUMERIC_D          0x20f
+
+#define KEY_CAMERA_FOCUS       0x210
+#define KEY_WPS_BUTTON         0x211   /* WiFi Protected Setup key */
+
+#define KEY_TOUCHPAD_TOGGLE    0x212   /* Request switch touchpad on or off */
+#define KEY_TOUCHPAD_ON                0x213
+#define KEY_TOUCHPAD_OFF       0x214
+
+#define KEY_CAMERA_ZOOMIN      0x215
+#define KEY_CAMERA_ZOOMOUT     0x216
+#define KEY_CAMERA_UP          0x217
+#define KEY_CAMERA_DOWN                0x218
+#define KEY_CAMERA_LEFT                0x219
+#define KEY_CAMERA_RIGHT       0x21a
+
+#define KEY_ATTENDANT_ON       0x21b
+#define KEY_ATTENDANT_OFF      0x21c
+#define KEY_ATTENDANT_TOGGLE   0x21d   /* Attendant call on or off */
+#define KEY_LIGHTS_TOGGLE      0x21e   /* Reading light on or off */
+
+#define BTN_DPAD_UP            0x220
+#define BTN_DPAD_DOWN          0x221
+#define BTN_DPAD_LEFT          0x222
+#define BTN_DPAD_RIGHT         0x223
+
+#define KEY_ALS_TOGGLE         0x230   /* Ambient light sensor */
+
+#define KEY_BUTTONCONFIG               0x240   /* AL Button Configuration */
+#define KEY_TASKMANAGER                0x241   /* AL Task/Project Manager */
+#define KEY_JOURNAL            0x242   /* AL Log/Journal/Timecard */
+#define KEY_CONTROLPANEL               0x243   /* AL Control Panel */
+#define KEY_APPSELECT          0x244   /* AL Select Task/Application */
+#define KEY_SCREENSAVER                0x245   /* AL Screen Saver */
+#define KEY_VOICECOMMAND               0x246   /* Listening Voice Command */
+
+#define KEY_BRIGHTNESS_MIN             0x250   /* Set Brightness to Minimum */
+#define KEY_BRIGHTNESS_MAX             0x251   /* Set Brightness to Maximum */
+
+#define KEY_KBDINPUTASSIST_PREV                0x260
+#define KEY_KBDINPUTASSIST_NEXT                0x261
+#define KEY_KBDINPUTASSIST_PREVGROUP           0x262
+#define KEY_KBDINPUTASSIST_NEXTGROUP           0x263
+#define KEY_KBDINPUTASSIST_ACCEPT              0x264
+#define KEY_KBDINPUTASSIST_CANCEL              0x265
+
+#define BTN_TRIGGER_HAPPY              0x2c0
+#define BTN_TRIGGER_HAPPY1             0x2c0
+#define BTN_TRIGGER_HAPPY2             0x2c1
+#define BTN_TRIGGER_HAPPY3             0x2c2
+#define BTN_TRIGGER_HAPPY4             0x2c3
+#define BTN_TRIGGER_HAPPY5             0x2c4
+#define BTN_TRIGGER_HAPPY6             0x2c5
+#define BTN_TRIGGER_HAPPY7             0x2c6
+#define BTN_TRIGGER_HAPPY8             0x2c7
+#define BTN_TRIGGER_HAPPY9             0x2c8
+#define BTN_TRIGGER_HAPPY10            0x2c9
+#define BTN_TRIGGER_HAPPY11            0x2ca
+#define BTN_TRIGGER_HAPPY12            0x2cb
+#define BTN_TRIGGER_HAPPY13            0x2cc
+#define BTN_TRIGGER_HAPPY14            0x2cd
+#define BTN_TRIGGER_HAPPY15            0x2ce
+#define BTN_TRIGGER_HAPPY16            0x2cf
+#define BTN_TRIGGER_HAPPY17            0x2d0
+#define BTN_TRIGGER_HAPPY18            0x2d1
+#define BTN_TRIGGER_HAPPY19            0x2d2
+#define BTN_TRIGGER_HAPPY20            0x2d3
+#define BTN_TRIGGER_HAPPY21            0x2d4
+#define BTN_TRIGGER_HAPPY22            0x2d5
+#define BTN_TRIGGER_HAPPY23            0x2d6
+#define BTN_TRIGGER_HAPPY24            0x2d7
+#define BTN_TRIGGER_HAPPY25            0x2d8
+#define BTN_TRIGGER_HAPPY26            0x2d9
+#define BTN_TRIGGER_HAPPY27            0x2da
+#define BTN_TRIGGER_HAPPY28            0x2db
+#define BTN_TRIGGER_HAPPY29            0x2dc
+#define BTN_TRIGGER_HAPPY30            0x2dd
+#define BTN_TRIGGER_HAPPY31            0x2de
+#define BTN_TRIGGER_HAPPY32            0x2df
+#define BTN_TRIGGER_HAPPY33            0x2e0
+#define BTN_TRIGGER_HAPPY34            0x2e1
+#define BTN_TRIGGER_HAPPY35            0x2e2
+#define BTN_TRIGGER_HAPPY36            0x2e3
+#define BTN_TRIGGER_HAPPY37            0x2e4
+#define BTN_TRIGGER_HAPPY38            0x2e5
+#define BTN_TRIGGER_HAPPY39            0x2e6
+#define BTN_TRIGGER_HAPPY40            0x2e7
+
+/* We avoid low common keys in module aliases so they don't get huge. */
+#define KEY_MIN_INTERESTING    KEY_MUTE
+#define KEY_MAX                        0x2ff
+#define KEY_CNT                        (KEY_MAX+1)
+
+/*
+ * Relative axes
+ */
+
+#define REL_X                  0x00
+#define REL_Y                  0x01
+#define REL_Z                  0x02
+#define REL_RX                 0x03
+#define REL_RY                 0x04
+#define REL_RZ                 0x05
+#define REL_HWHEEL             0x06
+#define REL_DIAL               0x07
+#define REL_WHEEL              0x08
+#define REL_MISC               0x09
+#define REL_MAX                        0x0f
+#define REL_CNT                        (REL_MAX+1)
+
+/*
+ * Absolute axes
+ */
+
+#define ABS_X                  0x00
+#define ABS_Y                  0x01
+#define ABS_Z                  0x02
+#define ABS_RX                 0x03
+#define ABS_RY                 0x04
+#define ABS_RZ                 0x05
+#define ABS_THROTTLE           0x06
+#define ABS_RUDDER             0x07
+#define ABS_WHEEL              0x08
+#define ABS_GAS                        0x09
+#define ABS_BRAKE              0x0a
+#define ABS_HAT0X              0x10
+#define ABS_HAT0Y              0x11
+#define ABS_HAT1X              0x12
+#define ABS_HAT1Y              0x13
+#define ABS_HAT2X              0x14
+#define ABS_HAT2Y              0x15
+#define ABS_HAT3X              0x16
+#define ABS_HAT3Y              0x17
+#define ABS_PRESSURE           0x18
+#define ABS_DISTANCE           0x19
+#define ABS_TILT_X             0x1a
+#define ABS_TILT_Y             0x1b
+#define ABS_TOOL_WIDTH         0x1c
+
+#define ABS_VOLUME             0x20
+
+#define ABS_MISC               0x28
+
+#define ABS_MT_SLOT            0x2f    /* MT slot being modified */
+#define ABS_MT_TOUCH_MAJOR     0x30    /* Major axis of touching ellipse */
+#define ABS_MT_TOUCH_MINOR     0x31    /* Minor axis (omit if circular) */
+#define ABS_MT_WIDTH_MAJOR     0x32    /* Major axis of approaching ellipse */
+#define ABS_MT_WIDTH_MINOR     0x33    /* Minor axis (omit if circular) */
+#define ABS_MT_ORIENTATION     0x34    /* Ellipse orientation */
+#define ABS_MT_POSITION_X      0x35    /* Center X touch position */
+#define ABS_MT_POSITION_Y      0x36    /* Center Y touch position */
+#define ABS_MT_TOOL_TYPE       0x37    /* Type of touching device */
+#define ABS_MT_BLOB_ID         0x38    /* Group a set of packets as a blob */
+#define ABS_MT_TRACKING_ID     0x39    /* Unique ID of initiated contact */
+#define ABS_MT_PRESSURE                0x3a    /* Pressure on contact area */
+#define ABS_MT_DISTANCE                0x3b    /* Contact hover distance */
+#define ABS_MT_TOOL_X          0x3c    /* Center X tool position */
+#define ABS_MT_TOOL_Y          0x3d    /* Center Y tool position */
+
+
+#define ABS_MAX                        0x3f
+#define ABS_CNT                        (ABS_MAX+1)
+
+/*
+ * Switch events
+ */
+
+#define SW_LID                 0x00  /* set = lid shut */
+#define SW_TABLET_MODE         0x01  /* set = tablet mode */
+#define SW_HEADPHONE_INSERT    0x02  /* set = inserted */
+#define SW_RFKILL_ALL          0x03  /* rfkill master switch, type "any"
+                                        set = radio enabled */
+#define SW_RADIO               SW_RFKILL_ALL   /* deprecated */
+#define SW_MICROPHONE_INSERT   0x04  /* set = inserted */
+#define SW_DOCK                        0x05  /* set = plugged into dock */
+#define SW_LINEOUT_INSERT      0x06  /* set = inserted */
+#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
+#define SW_VIDEOOUT_INSERT     0x08  /* set = inserted */
+#define SW_CAMERA_LENS_COVER   0x09  /* set = lens covered */
+#define SW_KEYPAD_SLIDE                0x0a  /* set = keypad slide out */
+#define SW_FRONT_PROXIMITY     0x0b  /* set = front proximity sensor active */
+#define SW_ROTATE_LOCK         0x0c  /* set = rotate locked/disabled */
+#define SW_LINEIN_INSERT       0x0d  /* set = inserted */
+#define SW_MUTE_DEVICE         0x0e  /* set = device disabled */
+#define SW_MAX                 0x0f
+#define SW_CNT                 (SW_MAX+1)
+
+/*
+ * Misc events
+ */
+
+#define MSC_SERIAL             0x00
+#define MSC_PULSELED           0x01
+#define MSC_GESTURE            0x02
+#define MSC_RAW                        0x03
+#define MSC_SCAN               0x04
+#define MSC_TIMESTAMP          0x05
+#define MSC_MAX                        0x07
+#define MSC_CNT                        (MSC_MAX+1)
+
+/*
+ * LEDs
+ */
+
+#define LED_NUML               0x00
+#define LED_CAPSL              0x01
+#define LED_SCROLLL            0x02
+#define LED_COMPOSE            0x03
+#define LED_KANA               0x04
+#define LED_SLEEP              0x05
+#define LED_SUSPEND            0x06
+#define LED_MUTE               0x07
+#define LED_MISC               0x08
+#define LED_MAIL               0x09
+#define LED_CHARGING           0x0a
+#define LED_MAX                        0x0f
+#define LED_CNT                        (LED_MAX+1)
+
+/*
+ * Autorepeat values
+ */
+
+#define REP_DELAY              0x00
+#define REP_PERIOD             0x01
+#define REP_MAX                        0x01
+#define REP_CNT                        (REP_MAX+1)
+
+/*
+ * Sounds
+ */
+
+#define SND_CLICK              0x00
+#define SND_BELL               0x01
+#define SND_TONE               0x02
+#define SND_MAX                        0x07
+#define SND_CNT                        (SND_MAX+1)
+
+#endif
index 731417c025f6feff03ea257b46abde05c7a06b7d..2758687300b474dab6d87234ea79ed4ab926ac93 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #endif
 
+#include "input-event-codes.h"
 
 /*
  * The event structure itself
@@ -97,6 +98,12 @@ struct input_keymap_entry {
        __u8  scancode[32];
 };
 
+struct input_mask {
+       __u32 type;
+       __u32 codes_size;
+       __u64 codes_ptr;
+};
+
 #define EVIOCGVERSION          _IOR('E', 0x01, int)                    /* get driver version */
 #define EVIOCGID               _IOR('E', 0x02, struct input_id)        /* get device ID */
 #define EVIOCGREP              _IOR('E', 0x03, unsigned int[2])        /* get repeat settings */
@@ -147,801 +154,68 @@ struct input_keymap_entry {
 #define EVIOCGABS(abs)         _IOR('E', 0x40 + (abs), struct input_absinfo)   /* get abs value/limits */
 #define EVIOCSABS(abs)         _IOW('E', 0xc0 + (abs), struct input_absinfo)   /* set abs value/limits */
 
-#define EVIOCSFF               _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))   /* send a force effect to a force feedback device */
+#define EVIOCSFF               _IOW('E', 0x80, struct ff_effect)       /* send a force effect to a force feedback device */
 #define EVIOCRMFF              _IOW('E', 0x81, int)                    /* Erase a force effect */
 #define EVIOCGEFFECTS          _IOR('E', 0x84, int)                    /* Report number of effects playable at the same time */
 
 #define EVIOCGRAB              _IOW('E', 0x90, int)                    /* Grab/Release device */
 #define EVIOCREVOKE            _IOW('E', 0x91, int)                    /* Revoke device access */
 
-#define EVIOCSCLOCKID          _IOW('E', 0xa0, int)                    /* Set clockid to be used for timestamps */
-
-/*
- * Device properties and quirks
- */
-
-#define INPUT_PROP_POINTER             0x00    /* needs a pointer */
-#define INPUT_PROP_DIRECT              0x01    /* direct input devices */
-#define INPUT_PROP_BUTTONPAD           0x02    /* has button(s) under pad */
-#define INPUT_PROP_SEMI_MT             0x03    /* touch rectangle only */
-#define INPUT_PROP_TOPBUTTONPAD                0x04    /* softbuttons at top of pad */
-#define INPUT_PROP_POINTING_STICK      0x05    /* is a pointing stick */
-#define INPUT_PROP_ACCELEROMETER       0x06    /* has accelerometer */
-
-#define INPUT_PROP_MAX                 0x1f
-#define INPUT_PROP_CNT                 (INPUT_PROP_MAX + 1)
-
-/*
- * Event types
- */
-
-#define EV_SYN                 0x00
-#define EV_KEY                 0x01
-#define EV_REL                 0x02
-#define EV_ABS                 0x03
-#define EV_MSC                 0x04
-#define EV_SW                  0x05
-#define EV_LED                 0x11
-#define EV_SND                 0x12
-#define EV_REP                 0x14
-#define EV_FF                  0x15
-#define EV_PWR                 0x16
-#define EV_FF_STATUS           0x17
-#define EV_MAX                 0x1f
-#define EV_CNT                 (EV_MAX+1)
-
-/*
- * Synchronization events.
- */
-
-#define SYN_REPORT             0
-#define SYN_CONFIG             1
-#define SYN_MT_REPORT          2
-#define SYN_DROPPED            3
-#define SYN_MAX                        0xf
-#define SYN_CNT                        (SYN_MAX+1)
-
-/*
- * Keys and buttons
+/**
+ * EVIOCGMASK - Retrieve current event mask
  *
- * Most of the keys/buttons are modeled after USB HUT 1.12
- * (see http://www.usb.org/developers/hidpage).
- * Abbreviations in the comments:
- * AC - Application Control
- * AL - Application Launch Button
- * SC - System Control
- */
-
-#define KEY_RESERVED           0
-#define KEY_ESC                        1
-#define KEY_1                  2
-#define KEY_2                  3
-#define KEY_3                  4
-#define KEY_4                  5
-#define KEY_5                  6
-#define KEY_6                  7
-#define KEY_7                  8
-#define KEY_8                  9
-#define KEY_9                  10
-#define KEY_0                  11
-#define KEY_MINUS              12
-#define KEY_EQUAL              13
-#define KEY_BACKSPACE          14
-#define KEY_TAB                        15
-#define KEY_Q                  16
-#define KEY_W                  17
-#define KEY_E                  18
-#define KEY_R                  19
-#define KEY_T                  20
-#define KEY_Y                  21
-#define KEY_U                  22
-#define KEY_I                  23
-#define KEY_O                  24
-#define KEY_P                  25
-#define KEY_LEFTBRACE          26
-#define KEY_RIGHTBRACE         27
-#define KEY_ENTER              28
-#define KEY_LEFTCTRL           29
-#define KEY_A                  30
-#define KEY_S                  31
-#define KEY_D                  32
-#define KEY_F                  33
-#define KEY_G                  34
-#define KEY_H                  35
-#define KEY_J                  36
-#define KEY_K                  37
-#define KEY_L                  38
-#define KEY_SEMICOLON          39
-#define KEY_APOSTROPHE         40
-#define KEY_GRAVE              41
-#define KEY_LEFTSHIFT          42
-#define KEY_BACKSLASH          43
-#define KEY_Z                  44
-#define KEY_X                  45
-#define KEY_C                  46
-#define KEY_V                  47
-#define KEY_B                  48
-#define KEY_N                  49
-#define KEY_M                  50
-#define KEY_COMMA              51
-#define KEY_DOT                        52
-#define KEY_SLASH              53
-#define KEY_RIGHTSHIFT         54
-#define KEY_KPASTERISK         55
-#define KEY_LEFTALT            56
-#define KEY_SPACE              57
-#define KEY_CAPSLOCK           58
-#define KEY_F1                 59
-#define KEY_F2                 60
-#define KEY_F3                 61
-#define KEY_F4                 62
-#define KEY_F5                 63
-#define KEY_F6                 64
-#define KEY_F7                 65
-#define KEY_F8                 66
-#define KEY_F9                 67
-#define KEY_F10                        68
-#define KEY_NUMLOCK            69
-#define KEY_SCROLLLOCK         70
-#define KEY_KP7                        71
-#define KEY_KP8                        72
-#define KEY_KP9                        73
-#define KEY_KPMINUS            74
-#define KEY_KP4                        75
-#define KEY_KP5                        76
-#define KEY_KP6                        77
-#define KEY_KPPLUS             78
-#define KEY_KP1                        79
-#define KEY_KP2                        80
-#define KEY_KP3                        81
-#define KEY_KP0                        82
-#define KEY_KPDOT              83
-
-#define KEY_ZENKAKUHANKAKU     85
-#define KEY_102ND              86
-#define KEY_F11                        87
-#define KEY_F12                        88
-#define KEY_RO                 89
-#define KEY_KATAKANA           90
-#define KEY_HIRAGANA           91
-#define KEY_HENKAN             92
-#define KEY_KATAKANAHIRAGANA   93
-#define KEY_MUHENKAN           94
-#define KEY_KPJPCOMMA          95
-#define KEY_KPENTER            96
-#define KEY_RIGHTCTRL          97
-#define KEY_KPSLASH            98
-#define KEY_SYSRQ              99
-#define KEY_RIGHTALT           100
-#define KEY_LINEFEED           101
-#define KEY_HOME               102
-#define KEY_UP                 103
-#define KEY_PAGEUP             104
-#define KEY_LEFT               105
-#define KEY_RIGHT              106
-#define KEY_END                        107
-#define KEY_DOWN               108
-#define KEY_PAGEDOWN           109
-#define KEY_INSERT             110
-#define KEY_DELETE             111
-#define KEY_MACRO              112
-#define KEY_MUTE               113
-#define KEY_VOLUMEDOWN         114
-#define KEY_VOLUMEUP           115
-#define KEY_POWER              116     /* SC System Power Down */
-#define KEY_KPEQUAL            117
-#define KEY_KPPLUSMINUS                118
-#define KEY_PAUSE              119
-#define KEY_SCALE              120     /* AL Compiz Scale (Expose) */
-
-#define KEY_KPCOMMA            121
-#define KEY_HANGEUL            122
-#define KEY_HANGUEL            KEY_HANGEUL
-#define KEY_HANJA              123
-#define KEY_YEN                        124
-#define KEY_LEFTMETA           125
-#define KEY_RIGHTMETA          126
-#define KEY_COMPOSE            127
-
-#define KEY_STOP               128     /* AC Stop */
-#define KEY_AGAIN              129
-#define KEY_PROPS              130     /* AC Properties */
-#define KEY_UNDO               131     /* AC Undo */
-#define KEY_FRONT              132
-#define KEY_COPY               133     /* AC Copy */
-#define KEY_OPEN               134     /* AC Open */
-#define KEY_PASTE              135     /* AC Paste */
-#define KEY_FIND               136     /* AC Search */
-#define KEY_CUT                        137     /* AC Cut */
-#define KEY_HELP               138     /* AL Integrated Help Center */
-#define KEY_MENU               139     /* Menu (show menu) */
-#define KEY_CALC               140     /* AL Calculator */
-#define KEY_SETUP              141
-#define KEY_SLEEP              142     /* SC System Sleep */
-#define KEY_WAKEUP             143     /* System Wake Up */
-#define KEY_FILE               144     /* AL Local Machine Browser */
-#define KEY_SENDFILE           145
-#define KEY_DELETEFILE         146
-#define KEY_XFER               147
-#define KEY_PROG1              148
-#define KEY_PROG2              149
-#define KEY_WWW                        150     /* AL Internet Browser */
-#define KEY_MSDOS              151
-#define KEY_COFFEE             152     /* AL Terminal Lock/Screensaver */
-#define KEY_SCREENLOCK         KEY_COFFEE
-#define KEY_ROTATE_DISPLAY     153     /* Display orientation for e.g. tablets */
-#define KEY_DIRECTION          KEY_ROTATE_DISPLAY
-#define KEY_CYCLEWINDOWS       154
-#define KEY_MAIL               155
-#define KEY_BOOKMARKS          156     /* AC Bookmarks */
-#define KEY_COMPUTER           157
-#define KEY_BACK               158     /* AC Back */
-#define KEY_FORWARD            159     /* AC Forward */
-#define KEY_CLOSECD            160
-#define KEY_EJECTCD            161
-#define KEY_EJECTCLOSECD       162
-#define KEY_NEXTSONG           163
-#define KEY_PLAYPAUSE          164
-#define KEY_PREVIOUSSONG       165
-#define KEY_STOPCD             166
-#define KEY_RECORD             167
-#define KEY_REWIND             168
-#define KEY_PHONE              169     /* Media Select Telephone */
-#define KEY_ISO                        170
-#define KEY_CONFIG             171     /* AL Consumer Control Configuration */
-#define KEY_HOMEPAGE           172     /* AC Home */
-#define KEY_REFRESH            173     /* AC Refresh */
-#define KEY_EXIT               174     /* AC Exit */
-#define KEY_MOVE               175
-#define KEY_EDIT               176
-#define KEY_SCROLLUP           177
-#define KEY_SCROLLDOWN         178
-#define KEY_KPLEFTPAREN                179
-#define KEY_KPRIGHTPAREN       180
-#define KEY_NEW                        181     /* AC New */
-#define KEY_REDO               182     /* AC Redo/Repeat */
-
-#define KEY_F13                        183
-#define KEY_F14                        184
-#define KEY_F15                        185
-#define KEY_F16                        186
-#define KEY_F17                        187
-#define KEY_F18                        188
-#define KEY_F19                        189
-#define KEY_F20                        190
-#define KEY_F21                        191
-#define KEY_F22                        192
-#define KEY_F23                        193
-#define KEY_F24                        194
-
-#define KEY_PLAYCD             200
-#define KEY_PAUSECD            201
-#define KEY_PROG3              202
-#define KEY_PROG4              203
-#define KEY_DASHBOARD          204     /* AL Dashboard */
-#define KEY_SUSPEND            205
-#define KEY_CLOSE              206     /* AC Close */
-#define KEY_PLAY               207
-#define KEY_FASTFORWARD                208
-#define KEY_BASSBOOST          209
-#define KEY_PRINT              210     /* AC Print */
-#define KEY_HP                 211
-#define KEY_CAMERA             212
-#define KEY_SOUND              213
-#define KEY_QUESTION           214
-#define KEY_EMAIL              215
-#define KEY_CHAT               216
-#define KEY_SEARCH             217
-#define KEY_CONNECT            218
-#define KEY_FINANCE            219     /* AL Checkbook/Finance */
-#define KEY_SPORT              220
-#define KEY_SHOP               221
-#define KEY_ALTERASE           222
-#define KEY_CANCEL             223     /* AC Cancel */
-#define KEY_BRIGHTNESSDOWN     224
-#define KEY_BRIGHTNESSUP       225
-#define KEY_MEDIA              226
-
-#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
-                                          outputs (Monitor/LCD/TV-out/etc) */
-#define KEY_KBDILLUMTOGGLE     228
-#define KEY_KBDILLUMDOWN       229
-#define KEY_KBDILLUMUP         230
-
-#define KEY_SEND               231     /* AC Send */
-#define KEY_REPLY              232     /* AC Reply */
-#define KEY_FORWARDMAIL                233     /* AC Forward Msg */
-#define KEY_SAVE               234     /* AC Save */
-#define KEY_DOCUMENTS          235
-
-#define KEY_BATTERY            236
-
-#define KEY_BLUETOOTH          237
-#define KEY_WLAN               238
-#define KEY_UWB                        239
-
-#define KEY_UNKNOWN            240
-
-#define KEY_VIDEO_NEXT         241     /* drive next video source */
-#define KEY_VIDEO_PREV         242     /* drive previous video source */
-#define KEY_BRIGHTNESS_CYCLE   243     /* brightness up, after max is min */
-#define KEY_BRIGHTNESS_AUTO    244     /* Set Auto Brightness: manual
-                                         brightness control is off,
-                                         rely on ambient */
-#define KEY_BRIGHTNESS_ZERO    KEY_BRIGHTNESS_AUTO
-#define KEY_DISPLAY_OFF                245     /* display device to off state */
-
-#define KEY_WWAN               246     /* Wireless WAN (LTE, UMTS, GSM, etc.) */
-#define KEY_WIMAX              KEY_WWAN
-#define KEY_RFKILL             247     /* Key that controls all radios */
-
-#define KEY_MICMUTE            248     /* Mute / unmute the microphone */
-
-/* Code 255 is reserved for special needs of AT keyboard driver */
-
-#define BTN_MISC               0x100
-#define BTN_0                  0x100
-#define BTN_1                  0x101
-#define BTN_2                  0x102
-#define BTN_3                  0x103
-#define BTN_4                  0x104
-#define BTN_5                  0x105
-#define BTN_6                  0x106
-#define BTN_7                  0x107
-#define BTN_8                  0x108
-#define BTN_9                  0x109
-
-#define BTN_MOUSE              0x110
-#define BTN_LEFT               0x110
-#define BTN_RIGHT              0x111
-#define BTN_MIDDLE             0x112
-#define BTN_SIDE               0x113
-#define BTN_EXTRA              0x114
-#define BTN_FORWARD            0x115
-#define BTN_BACK               0x116
-#define BTN_TASK               0x117
-
-#define BTN_JOYSTICK           0x120
-#define BTN_TRIGGER            0x120
-#define BTN_THUMB              0x121
-#define BTN_THUMB2             0x122
-#define BTN_TOP                        0x123
-#define BTN_TOP2               0x124
-#define BTN_PINKIE             0x125
-#define BTN_BASE               0x126
-#define BTN_BASE2              0x127
-#define BTN_BASE3              0x128
-#define BTN_BASE4              0x129
-#define BTN_BASE5              0x12a
-#define BTN_BASE6              0x12b
-#define BTN_DEAD               0x12f
-
-#define BTN_GAMEPAD            0x130
-#define BTN_SOUTH              0x130
-#define BTN_A                  BTN_SOUTH
-#define BTN_EAST               0x131
-#define BTN_B                  BTN_EAST
-#define BTN_C                  0x132
-#define BTN_NORTH              0x133
-#define BTN_X                  BTN_NORTH
-#define BTN_WEST               0x134
-#define BTN_Y                  BTN_WEST
-#define BTN_Z                  0x135
-#define BTN_TL                 0x136
-#define BTN_TR                 0x137
-#define BTN_TL2                        0x138
-#define BTN_TR2                        0x139
-#define BTN_SELECT             0x13a
-#define BTN_START              0x13b
-#define BTN_MODE               0x13c
-#define BTN_THUMBL             0x13d
-#define BTN_THUMBR             0x13e
-
-#define BTN_DIGI               0x140
-#define BTN_TOOL_PEN           0x140
-#define BTN_TOOL_RUBBER                0x141
-#define BTN_TOOL_BRUSH         0x142
-#define BTN_TOOL_PENCIL                0x143
-#define BTN_TOOL_AIRBRUSH      0x144
-#define BTN_TOOL_FINGER                0x145
-#define BTN_TOOL_MOUSE         0x146
-#define BTN_TOOL_LENS          0x147
-#define BTN_TOOL_QUINTTAP      0x148   /* Five fingers on trackpad */
-#define BTN_TOUCH              0x14a
-#define BTN_STYLUS             0x14b
-#define BTN_STYLUS2            0x14c
-#define BTN_TOOL_DOUBLETAP     0x14d
-#define BTN_TOOL_TRIPLETAP     0x14e
-#define BTN_TOOL_QUADTAP       0x14f   /* Four fingers on trackpad */
-
-#define BTN_WHEEL              0x150
-#define BTN_GEAR_DOWN          0x150
-#define BTN_GEAR_UP            0x151
-
-#define KEY_OK                 0x160
-#define KEY_SELECT             0x161
-#define KEY_GOTO               0x162
-#define KEY_CLEAR              0x163
-#define KEY_POWER2             0x164
-#define KEY_OPTION             0x165
-#define KEY_INFO               0x166   /* AL OEM Features/Tips/Tutorial */
-#define KEY_TIME               0x167
-#define KEY_VENDOR             0x168
-#define KEY_ARCHIVE            0x169
-#define KEY_PROGRAM            0x16a   /* Media Select Program Guide */
-#define KEY_CHANNEL            0x16b
-#define KEY_FAVORITES          0x16c
-#define KEY_EPG                        0x16d
-#define KEY_PVR                        0x16e   /* Media Select Home */
-#define KEY_MHP                        0x16f
-#define KEY_LANGUAGE           0x170
-#define KEY_TITLE              0x171
-#define KEY_SUBTITLE           0x172
-#define KEY_ANGLE              0x173
-#define KEY_ZOOM               0x174
-#define KEY_MODE               0x175
-#define KEY_KEYBOARD           0x176
-#define KEY_SCREEN             0x177
-#define KEY_PC                 0x178   /* Media Select Computer */
-#define KEY_TV                 0x179   /* Media Select TV */
-#define KEY_TV2                        0x17a   /* Media Select Cable */
-#define KEY_VCR                        0x17b   /* Media Select VCR */
-#define KEY_VCR2               0x17c   /* VCR Plus */
-#define KEY_SAT                        0x17d   /* Media Select Satellite */
-#define KEY_SAT2               0x17e
-#define KEY_CD                 0x17f   /* Media Select CD */
-#define KEY_TAPE               0x180   /* Media Select Tape */
-#define KEY_RADIO              0x181
-#define KEY_TUNER              0x182   /* Media Select Tuner */
-#define KEY_PLAYER             0x183
-#define KEY_TEXT               0x184
-#define KEY_DVD                        0x185   /* Media Select DVD */
-#define KEY_AUX                        0x186
-#define KEY_MP3                        0x187
-#define KEY_AUDIO              0x188   /* AL Audio Browser */
-#define KEY_VIDEO              0x189   /* AL Movie Browser */
-#define KEY_DIRECTORY          0x18a
-#define KEY_LIST               0x18b
-#define KEY_MEMO               0x18c   /* Media Select Messages */
-#define KEY_CALENDAR           0x18d
-#define KEY_RED                        0x18e
-#define KEY_GREEN              0x18f
-#define KEY_YELLOW             0x190
-#define KEY_BLUE               0x191
-#define KEY_CHANNELUP          0x192   /* Channel Increment */
-#define KEY_CHANNELDOWN                0x193   /* Channel Decrement */
-#define KEY_FIRST              0x194
-#define KEY_LAST               0x195   /* Recall Last */
-#define KEY_AB                 0x196
-#define KEY_NEXT               0x197
-#define KEY_RESTART            0x198
-#define KEY_SLOW               0x199
-#define KEY_SHUFFLE            0x19a
-#define KEY_BREAK              0x19b
-#define KEY_PREVIOUS           0x19c
-#define KEY_DIGITS             0x19d
-#define KEY_TEEN               0x19e
-#define KEY_TWEN               0x19f
-#define KEY_VIDEOPHONE         0x1a0   /* Media Select Video Phone */
-#define KEY_GAMES              0x1a1   /* Media Select Games */
-#define KEY_ZOOMIN             0x1a2   /* AC Zoom In */
-#define KEY_ZOOMOUT            0x1a3   /* AC Zoom Out */
-#define KEY_ZOOMRESET          0x1a4   /* AC Zoom */
-#define KEY_WORDPROCESSOR      0x1a5   /* AL Word Processor */
-#define KEY_EDITOR             0x1a6   /* AL Text Editor */
-#define KEY_SPREADSHEET                0x1a7   /* AL Spreadsheet */
-#define KEY_GRAPHICSEDITOR     0x1a8   /* AL Graphics Editor */
-#define KEY_PRESENTATION       0x1a9   /* AL Presentation App */
-#define KEY_DATABASE           0x1aa   /* AL Database App */
-#define KEY_NEWS               0x1ab   /* AL Newsreader */
-#define KEY_VOICEMAIL          0x1ac   /* AL Voicemail */
-#define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
-#define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
-#define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
-#define KEY_BRIGHTNESS_TOGGLE  KEY_DISPLAYTOGGLE
-#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
-#define KEY_LOGOFF             0x1b1   /* AL Logoff */
-
-#define KEY_DOLLAR             0x1b2
-#define KEY_EURO               0x1b3
-
-#define KEY_FRAMEBACK          0x1b4   /* Consumer - transport controls */
-#define KEY_FRAMEFORWARD       0x1b5
-#define KEY_CONTEXT_MENU       0x1b6   /* GenDesc - system context menu */
-#define KEY_MEDIA_REPEAT       0x1b7   /* Consumer - transport control */
-#define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
-#define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
-#define KEY_IMAGES             0x1ba   /* AL Image Browser */
-
-#define KEY_DEL_EOL            0x1c0
-#define KEY_DEL_EOS            0x1c1
-#define KEY_INS_LINE           0x1c2
-#define KEY_DEL_LINE           0x1c3
-
-#define KEY_FN                 0x1d0
-#define KEY_FN_ESC             0x1d1
-#define KEY_FN_F1              0x1d2
-#define KEY_FN_F2              0x1d3
-#define KEY_FN_F3              0x1d4
-#define KEY_FN_F4              0x1d5
-#define KEY_FN_F5              0x1d6
-#define KEY_FN_F6              0x1d7
-#define KEY_FN_F7              0x1d8
-#define KEY_FN_F8              0x1d9
-#define KEY_FN_F9              0x1da
-#define KEY_FN_F10             0x1db
-#define KEY_FN_F11             0x1dc
-#define KEY_FN_F12             0x1dd
-#define KEY_FN_1               0x1de
-#define KEY_FN_2               0x1df
-#define KEY_FN_D               0x1e0
-#define KEY_FN_E               0x1e1
-#define KEY_FN_F               0x1e2
-#define KEY_FN_S               0x1e3
-#define KEY_FN_B               0x1e4
-
-#define KEY_BRL_DOT1           0x1f1
-#define KEY_BRL_DOT2           0x1f2
-#define KEY_BRL_DOT3           0x1f3
-#define KEY_BRL_DOT4           0x1f4
-#define KEY_BRL_DOT5           0x1f5
-#define KEY_BRL_DOT6           0x1f6
-#define KEY_BRL_DOT7           0x1f7
-#define KEY_BRL_DOT8           0x1f8
-#define KEY_BRL_DOT9           0x1f9
-#define KEY_BRL_DOT10          0x1fa
-
-#define KEY_NUMERIC_0          0x200   /* used by phones, remote controls, */
-#define KEY_NUMERIC_1          0x201   /* and other keypads */
-#define KEY_NUMERIC_2          0x202
-#define KEY_NUMERIC_3          0x203
-#define KEY_NUMERIC_4          0x204
-#define KEY_NUMERIC_5          0x205
-#define KEY_NUMERIC_6          0x206
-#define KEY_NUMERIC_7          0x207
-#define KEY_NUMERIC_8          0x208
-#define KEY_NUMERIC_9          0x209
-#define KEY_NUMERIC_STAR       0x20a
-#define KEY_NUMERIC_POUND      0x20b
-#define KEY_NUMERIC_A          0x20c   /* Phone key A - HUT Telephony 0xb9 */
-#define KEY_NUMERIC_B          0x20d
-#define KEY_NUMERIC_C          0x20e
-#define KEY_NUMERIC_D          0x20f
-
-#define KEY_CAMERA_FOCUS       0x210
-#define KEY_WPS_BUTTON         0x211   /* WiFi Protected Setup key */
-
-#define KEY_TOUCHPAD_TOGGLE    0x212   /* Request switch touchpad on or off */
-#define KEY_TOUCHPAD_ON                0x213
-#define KEY_TOUCHPAD_OFF       0x214
-
-#define KEY_CAMERA_ZOOMIN      0x215
-#define KEY_CAMERA_ZOOMOUT     0x216
-#define KEY_CAMERA_UP          0x217
-#define KEY_CAMERA_DOWN                0x218
-#define KEY_CAMERA_LEFT                0x219
-#define KEY_CAMERA_RIGHT       0x21a
-
-#define KEY_ATTENDANT_ON       0x21b
-#define KEY_ATTENDANT_OFF      0x21c
-#define KEY_ATTENDANT_TOGGLE   0x21d   /* Attendant call on or off */
-#define KEY_LIGHTS_TOGGLE      0x21e   /* Reading light on or off */
-
-#define BTN_DPAD_UP            0x220
-#define BTN_DPAD_DOWN          0x221
-#define BTN_DPAD_LEFT          0x222
-#define BTN_DPAD_RIGHT         0x223
-
-#define KEY_ALS_TOGGLE         0x230   /* Ambient light sensor */
-
-#define KEY_BUTTONCONFIG               0x240   /* AL Button Configuration */
-#define KEY_TASKMANAGER                0x241   /* AL Task/Project Manager */
-#define KEY_JOURNAL            0x242   /* AL Log/Journal/Timecard */
-#define KEY_CONTROLPANEL               0x243   /* AL Control Panel */
-#define KEY_APPSELECT          0x244   /* AL Select Task/Application */
-#define KEY_SCREENSAVER                0x245   /* AL Screen Saver */
-#define KEY_VOICECOMMAND               0x246   /* Listening Voice Command */
-
-#define KEY_BRIGHTNESS_MIN             0x250   /* Set Brightness to Minimum */
-#define KEY_BRIGHTNESS_MAX             0x251   /* Set Brightness to Maximum */
-
-#define KEY_KBDINPUTASSIST_PREV                0x260
-#define KEY_KBDINPUTASSIST_NEXT                0x261
-#define KEY_KBDINPUTASSIST_PREVGROUP           0x262
-#define KEY_KBDINPUTASSIST_NEXTGROUP           0x263
-#define KEY_KBDINPUTASSIST_ACCEPT              0x264
-#define KEY_KBDINPUTASSIST_CANCEL              0x265
-
-#define BTN_TRIGGER_HAPPY              0x2c0
-#define BTN_TRIGGER_HAPPY1             0x2c0
-#define BTN_TRIGGER_HAPPY2             0x2c1
-#define BTN_TRIGGER_HAPPY3             0x2c2
-#define BTN_TRIGGER_HAPPY4             0x2c3
-#define BTN_TRIGGER_HAPPY5             0x2c4
-#define BTN_TRIGGER_HAPPY6             0x2c5
-#define BTN_TRIGGER_HAPPY7             0x2c6
-#define BTN_TRIGGER_HAPPY8             0x2c7
-#define BTN_TRIGGER_HAPPY9             0x2c8
-#define BTN_TRIGGER_HAPPY10            0x2c9
-#define BTN_TRIGGER_HAPPY11            0x2ca
-#define BTN_TRIGGER_HAPPY12            0x2cb
-#define BTN_TRIGGER_HAPPY13            0x2cc
-#define BTN_TRIGGER_HAPPY14            0x2cd
-#define BTN_TRIGGER_HAPPY15            0x2ce
-#define BTN_TRIGGER_HAPPY16            0x2cf
-#define BTN_TRIGGER_HAPPY17            0x2d0
-#define BTN_TRIGGER_HAPPY18            0x2d1
-#define BTN_TRIGGER_HAPPY19            0x2d2
-#define BTN_TRIGGER_HAPPY20            0x2d3
-#define BTN_TRIGGER_HAPPY21            0x2d4
-#define BTN_TRIGGER_HAPPY22            0x2d5
-#define BTN_TRIGGER_HAPPY23            0x2d6
-#define BTN_TRIGGER_HAPPY24            0x2d7
-#define BTN_TRIGGER_HAPPY25            0x2d8
-#define BTN_TRIGGER_HAPPY26            0x2d9
-#define BTN_TRIGGER_HAPPY27            0x2da
-#define BTN_TRIGGER_HAPPY28            0x2db
-#define BTN_TRIGGER_HAPPY29            0x2dc
-#define BTN_TRIGGER_HAPPY30            0x2dd
-#define BTN_TRIGGER_HAPPY31            0x2de
-#define BTN_TRIGGER_HAPPY32            0x2df
-#define BTN_TRIGGER_HAPPY33            0x2e0
-#define BTN_TRIGGER_HAPPY34            0x2e1
-#define BTN_TRIGGER_HAPPY35            0x2e2
-#define BTN_TRIGGER_HAPPY36            0x2e3
-#define BTN_TRIGGER_HAPPY37            0x2e4
-#define BTN_TRIGGER_HAPPY38            0x2e5
-#define BTN_TRIGGER_HAPPY39            0x2e6
-#define BTN_TRIGGER_HAPPY40            0x2e7
-
-/* We avoid low common keys in module aliases so they don't get huge. */
-#define KEY_MIN_INTERESTING    KEY_MUTE
-#define KEY_MAX                        0x2ff
-#define KEY_CNT                        (KEY_MAX+1)
-
-/*
- * Relative axes
- */
-
-#define REL_X                  0x00
-#define REL_Y                  0x01
-#define REL_Z                  0x02
-#define REL_RX                 0x03
-#define REL_RY                 0x04
-#define REL_RZ                 0x05
-#define REL_HWHEEL             0x06
-#define REL_DIAL               0x07
-#define REL_WHEEL              0x08
-#define REL_MISC               0x09
-#define REL_MAX                        0x0f
-#define REL_CNT                        (REL_MAX+1)
-
-/*
- * Absolute axes
- */
-
-#define ABS_X                  0x00
-#define ABS_Y                  0x01
-#define ABS_Z                  0x02
-#define ABS_RX                 0x03
-#define ABS_RY                 0x04
-#define ABS_RZ                 0x05
-#define ABS_THROTTLE           0x06
-#define ABS_RUDDER             0x07
-#define ABS_WHEEL              0x08
-#define ABS_GAS                        0x09
-#define ABS_BRAKE              0x0a
-#define ABS_HAT0X              0x10
-#define ABS_HAT0Y              0x11
-#define ABS_HAT1X              0x12
-#define ABS_HAT1Y              0x13
-#define ABS_HAT2X              0x14
-#define ABS_HAT2Y              0x15
-#define ABS_HAT3X              0x16
-#define ABS_HAT3Y              0x17
-#define ABS_PRESSURE           0x18
-#define ABS_DISTANCE           0x19
-#define ABS_TILT_X             0x1a
-#define ABS_TILT_Y             0x1b
-#define ABS_TOOL_WIDTH         0x1c
-
-#define ABS_VOLUME             0x20
-
-#define ABS_MISC               0x28
-
-#define ABS_MT_SLOT            0x2f    /* MT slot being modified */
-#define ABS_MT_TOUCH_MAJOR     0x30    /* Major axis of touching ellipse */
-#define ABS_MT_TOUCH_MINOR     0x31    /* Minor axis (omit if circular) */
-#define ABS_MT_WIDTH_MAJOR     0x32    /* Major axis of approaching ellipse */
-#define ABS_MT_WIDTH_MINOR     0x33    /* Minor axis (omit if circular) */
-#define ABS_MT_ORIENTATION     0x34    /* Ellipse orientation */
-#define ABS_MT_POSITION_X      0x35    /* Center X touch position */
-#define ABS_MT_POSITION_Y      0x36    /* Center Y touch position */
-#define ABS_MT_TOOL_TYPE       0x37    /* Type of touching device */
-#define ABS_MT_BLOB_ID         0x38    /* Group a set of packets as a blob */
-#define ABS_MT_TRACKING_ID     0x39    /* Unique ID of initiated contact */
-#define ABS_MT_PRESSURE                0x3a    /* Pressure on contact area */
-#define ABS_MT_DISTANCE                0x3b    /* Contact hover distance */
-#define ABS_MT_TOOL_X          0x3c    /* Center X tool position */
-#define ABS_MT_TOOL_Y          0x3d    /* Center Y tool position */
-
-
-#define ABS_MAX                        0x3f
-#define ABS_CNT                        (ABS_MAX+1)
-
-/*
- * Switch events
- */
-
-#define SW_LID                 0x00  /* set = lid shut */
-#define SW_TABLET_MODE         0x01  /* set = tablet mode */
-#define SW_HEADPHONE_INSERT    0x02  /* set = inserted */
-#define SW_RFKILL_ALL          0x03  /* rfkill master switch, type "any"
-                                        set = radio enabled */
-#define SW_RADIO               SW_RFKILL_ALL   /* deprecated */
-#define SW_MICROPHONE_INSERT   0x04  /* set = inserted */
-#define SW_DOCK                        0x05  /* set = plugged into dock */
-#define SW_LINEOUT_INSERT      0x06  /* set = inserted */
-#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
-#define SW_VIDEOOUT_INSERT     0x08  /* set = inserted */
-#define SW_CAMERA_LENS_COVER   0x09  /* set = lens covered */
-#define SW_KEYPAD_SLIDE                0x0a  /* set = keypad slide out */
-#define SW_FRONT_PROXIMITY     0x0b  /* set = front proximity sensor active */
-#define SW_ROTATE_LOCK         0x0c  /* set = rotate locked/disabled */
-#define SW_LINEIN_INSERT       0x0d  /* set = inserted */
-#define SW_MUTE_DEVICE         0x0e  /* set = device disabled */
-#define SW_MAX                 0x0f
-#define SW_CNT                 (SW_MAX+1)
-
-/*
- * Misc events
- */
-
-#define MSC_SERIAL             0x00
-#define MSC_PULSELED           0x01
-#define MSC_GESTURE            0x02
-#define MSC_RAW                        0x03
-#define MSC_SCAN               0x04
-#define MSC_TIMESTAMP          0x05
-#define MSC_MAX                        0x07
-#define MSC_CNT                        (MSC_MAX+1)
-
-/*
- * LEDs
- */
-
-#define LED_NUML               0x00
-#define LED_CAPSL              0x01
-#define LED_SCROLLL            0x02
-#define LED_COMPOSE            0x03
-#define LED_KANA               0x04
-#define LED_SLEEP              0x05
-#define LED_SUSPEND            0x06
-#define LED_MUTE               0x07
-#define LED_MISC               0x08
-#define LED_MAIL               0x09
-#define LED_CHARGING           0x0a
-#define LED_MAX                        0x0f
-#define LED_CNT                        (LED_MAX+1)
-
-/*
- * Autorepeat values
+ * This ioctl allows user to retrieve the current event mask for specific
+ * event type. The argument must be of type "struct input_mask" and
+ * specifies the event type to query, the address of the receive buffer and
+ * the size of the receive buffer.
+ *
+ * The event mask is a per-client mask that specifies which events are
+ * forwarded to the client. Each event code is represented by a single bit
+ * in the event mask. If the bit is set, the event is passed to the client
+ * normally. Otherwise, the event is filtered and will never be queued on
+ * the client's receive buffer.
+ *
+ * Event masks do not affect global state of the input device. They only
+ * affect the file descriptor they are applied to.
+ *
+ * The default event mask for a client has all bits set, i.e. all events
+ * are forwarded to the client. If the kernel is queried for an unknown
+ * event type or if the receive buffer is larger than the number of
+ * event codes known to the kernel, the kernel returns all zeroes for those
+ * codes.
+ *
+ * At maximum, codes_size bytes are copied.
+ *
+ * This ioctl may fail with ENODEV in case the file is revoked, EFAULT
+ * if the receive-buffer points to invalid memory, or EINVAL if the kernel
+ * does not implement the ioctl.
  */
+#define EVIOCGMASK             _IOR('E', 0x92, struct input_mask)      /* Get event-masks */
 
-#define REP_DELAY              0x00
-#define REP_PERIOD             0x01
-#define REP_MAX                        0x01
-#define REP_CNT                        (REP_MAX+1)
-
-/*
- * Sounds
+/**
+ * EVIOCSMASK - Set event mask
+ *
+ * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the
+ * current event mask, this changes the client's event mask for a specific
+ * type.  See EVIOCGMASK for a description of event-masks and the
+ * argument-type.
+ *
+ * This ioctl provides full forward compatibility. If the passed event type
+ * is unknown to the kernel, or if the number of event codes specified in
+ * the mask is bigger than what is known to the kernel, the ioctl is still
+ * accepted and applied. However, any unknown codes are left untouched and
+ * stay cleared. That means, the kernel always filters unknown codes
+ * regardless of what the client requests.  If the new mask doesn't cover
+ * all known event-codes, all remaining codes are automatically cleared and
+ * thus filtered.
+ *
+ * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is
+ * returned if the receive-buffer points to invalid memory. EINVAL is returned
+ * if the kernel does not implement the ioctl.
  */
+#define EVIOCSMASK             _IOW('E', 0x93, struct input_mask)      /* Set event-masks */
 
-#define SND_CLICK              0x00
-#define SND_BELL               0x01
-#define SND_TONE               0x02
-#define SND_MAX                        0x07
-#define SND_CNT                        (SND_MAX+1)
+#define EVIOCSCLOCKID          _IOW('E', 0xa0, int)                    /* Set clockid to be used for timestamps */
 
 /*
  * IDs.
@@ -1200,6 +474,14 @@ struct ff_effect {
 #define FF_GAIN                0x60
 #define FF_AUTOCENTER  0x61
 
+/*
+ * ff->playback(effect_id = FF_GAIN) is the first effect_id to
+ * cause a collision with another ff method, in this case ff->set_gain().
+ * Therefore the greatest safe value for effect_id is FF_GAIN - 1,
+ * and thus the total number of effects should never exceed FF_GAIN.
+ */
+#define FF_MAX_EFFECTS FF_GAIN
+
 #define FF_MAX         0x7f
 #define FF_CNT         (FF_MAX+1)
 
index 413417f3707bbfde6375dfc14098bc1e099b5b70..1becea86c73c9d217ef867fac0cce73e075c6427 100644 (file)
 #define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
 #define  PCI_CAP_ID_SATA       0x12    /* SATA Data/Index Conf. */
 #define  PCI_CAP_ID_AF         0x13    /* PCI Advanced Features */
-#define  PCI_CAP_ID_MAX                PCI_CAP_ID_AF
+#define  PCI_CAP_ID_EA         0x14    /* PCI Enhanced Allocation */
+#define  PCI_CAP_ID_MAX                PCI_CAP_ID_EA
 #define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
 #define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF         4
 #define  PCI_AF_STATUS_TP      0x01
 #define PCI_CAP_AF_SIZEOF      6       /* size of AF registers */
 
+/* PCI Enhanced Allocation registers */
+
+#define PCI_EA_NUM_ENT         2       /* Number of Capability Entries */
+#define  PCI_EA_NUM_ENT_MASK   0x3f    /* Num Entries Mask */
+#define PCI_EA_FIRST_ENT       4       /* First EA Entry in List */
+#define PCI_EA_FIRST_ENT_BRIDGE        8       /* First EA Entry for Bridges */
+#define  PCI_EA_ES             0x00000007 /* Entry Size */
+#define  PCI_EA_BEI            0x000000f0 /* BAR Equivalent Indicator */
+/* 0-5 map to BARs 0-5 respectively */
+#define   PCI_EA_BEI_BAR0              0
+#define   PCI_EA_BEI_BAR5              5
+#define   PCI_EA_BEI_BRIDGE            6       /* Resource behind bridge */
+#define   PCI_EA_BEI_ENI               7       /* Equivalent Not Indicated */
+#define   PCI_EA_BEI_ROM               8       /* Expansion ROM */
+/* 9-14 map to VF BARs 0-5 respectively */
+#define   PCI_EA_BEI_VF_BAR0           9
+#define   PCI_EA_BEI_VF_BAR5           14
+#define   PCI_EA_BEI_RESERVED          15      /* Reserved - Treat like ENI */
+#define  PCI_EA_PP             0x0000ff00      /* Primary Properties */
+#define  PCI_EA_SP             0x00ff0000      /* Secondary Properties */
+#define   PCI_EA_P_MEM                 0x00    /* Non-Prefetch Memory */
+#define   PCI_EA_P_MEM_PREFETCH                0x01    /* Prefetchable Memory */
+#define   PCI_EA_P_IO                  0x02    /* I/O Space */
+#define   PCI_EA_P_VF_MEM_PREFETCH     0x03    /* VF Prefetchable Memory */
+#define   PCI_EA_P_VF_MEM              0x04    /* VF Non-Prefetch Memory */
+#define   PCI_EA_P_BRIDGE_MEM          0x05    /* Bridge Non-Prefetch Memory */
+#define   PCI_EA_P_BRIDGE_MEM_PREFETCH 0x06    /* Bridge Prefetchable Memory */
+#define   PCI_EA_P_BRIDGE_IO           0x07    /* Bridge I/O Space */
+/* 0x08-0xfc reserved */
+#define   PCI_EA_P_MEM_RESERVED                0xfd    /* Reserved Memory */
+#define   PCI_EA_P_IO_RESERVED         0xfe    /* Reserved I/O Space */
+#define   PCI_EA_P_UNAVAILABLE         0xff    /* Entry Unavailable */
+#define  PCI_EA_WRITABLE       0x40000000      /* Writable: 1 = RW, 0 = HwInit */
+#define  PCI_EA_ENABLE         0x80000000      /* Enable for this entry */
+#define PCI_EA_BASE            4               /* Base Address Offset */
+#define PCI_EA_MAX_OFFSET      8               /* MaxOffset (resource length) */
+/* bit 0 is reserved */
+#define  PCI_EA_IS_64          0x00000002      /* 64-bit field flag */
+#define  PCI_EA_FIELD_MASK     0xfffffffc      /* For Base & Max Offset */
+
 /* PCI-X registers (Type 0 (non-bridge) devices) */
 
 #define PCI_X_CMD              2       /* Modes & Features */
diff --git a/include/uapi/linux/userio.h b/include/uapi/linux/userio.h
new file mode 100644 (file)
index 0000000..37d147f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * userio: virtual serio device support
+ * Copyright (C) 2015 Red Hat
+ * Copyright (C) 2015 Lyude (Stephen Chandler Paul) <cpaul@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; 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 Lesser General Public License for more
+ * details.
+ *
+ * This is the public header used for user-space communication with the userio
+ * driver. __attribute__((__packed__)) is used for all structs to keep ABI
+ * compatibility between all architectures.
+ */
+
+#ifndef _USERIO_H
+#define _USERIO_H
+
+#include <linux/types.h>
+
+enum userio_cmd_type {
+       USERIO_CMD_REGISTER = 0,
+       USERIO_CMD_SET_PORT_TYPE = 1,
+       USERIO_CMD_SEND_INTERRUPT = 2
+};
+
+/*
+ * userio Commands
+ * All commands sent to /dev/userio are encoded using this structure. The type
+ * field should contain a USERIO_CMD* value that indicates what kind of command
+ * is being sent to userio. The data field should contain the accompanying
+ * argument for the command, if there is one.
+ */
+struct userio_cmd {
+       __u8 type;
+       __u8 data;
+} __attribute__((__packed__));
+
+#endif /* !_USERIO_H */
index 83327c808c861938dfa36f6b7d7762656b811309..e71d5558cc23e66e5abae4e2bc3aa05efefd28e3 100644 (file)
@@ -20,8 +20,6 @@
 #ifndef __MTD_USER_H__
 #define __MTD_USER_H__
 
-#include <stdint.h>
-
 /* This file is blessed for inclusion by userspace */
 #include <mtd/mtd-abi.h>
 
index 978841eeaff10e1cffc5d1c6e37fbe175c3db197..8126c143a519f2d499d536d2d6e10b2587e9290f 100644 (file)
@@ -92,6 +92,7 @@ enum {
 enum {
        IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE,
        IB_USER_VERBS_EX_CMD_CREATE_CQ = IB_USER_VERBS_CMD_CREATE_CQ,
+       IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP,
        IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
        IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
 };
@@ -516,6 +517,25 @@ struct ib_uverbs_create_qp {
        __u64 driver_data[0];
 };
 
+struct ib_uverbs_ex_create_qp {
+       __u64 user_handle;
+       __u32 pd_handle;
+       __u32 send_cq_handle;
+       __u32 recv_cq_handle;
+       __u32 srq_handle;
+       __u32 max_send_wr;
+       __u32 max_recv_wr;
+       __u32 max_send_sge;
+       __u32 max_recv_sge;
+       __u32 max_inline_data;
+       __u8  sq_sig_all;
+       __u8  qp_type;
+       __u8  is_srq;
+       __u8 reserved;
+       __u32 comp_mask;
+       __u32 create_flags;
+};
+
 struct ib_uverbs_open_qp {
        __u64 response;
        __u64 user_handle;
@@ -538,6 +558,12 @@ struct ib_uverbs_create_qp_resp {
        __u32 reserved;
 };
 
+struct ib_uverbs_ex_create_qp_resp {
+       struct ib_uverbs_create_qp_resp base;
+       __u32 comp_mask;
+       __u32 response_length;
+};
+
 /*
  * This struct needs to remain a multiple of 8 bytes to keep the
  * alignment of the modify QP parameters.
index 247c50bd60f0d067ad8884dbe4574adf0bfcf596..26539a7e488081933f151c570220ff4561deec40 100644 (file)
@@ -83,7 +83,7 @@
 #define SND_SOC_TPLG_NUM_TEXTS         16
 
 /* ABI version */
-#define SND_SOC_TPLG_ABI_VERSION       0x3
+#define SND_SOC_TPLG_ABI_VERSION       0x4
 
 /* Max size of TLV data */
 #define SND_SOC_TPLG_TLV_SIZE          32
 #define SND_SOC_TPLG_TYPE_PCM          7
 #define SND_SOC_TPLG_TYPE_MANIFEST     8
 #define SND_SOC_TPLG_TYPE_CODEC_LINK   9
-#define SND_SOC_TPLG_TYPE_PDATA                10
+#define SND_SOC_TPLG_TYPE_BACKEND_LINK 10
+#define SND_SOC_TPLG_TYPE_PDATA                11
 #define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_PDATA
 
 /* vendor block IDs - please add new vendor types to end */
@@ -198,7 +199,7 @@ struct snd_soc_tplg_ctl_hdr {
 struct snd_soc_tplg_stream_caps {
        __le32 size;            /* in bytes of this structure */
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       __le64 formats[SND_SOC_TPLG_MAX_FORMATS];       /* supported formats SNDRV_PCM_FMTBIT_* */
+       __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */
        __le32 rates;           /* supported rates SNDRV_PCM_RATE_* */
        __le32 rate_min;        /* min rate */
        __le32 rate_max;        /* max rate */
@@ -217,23 +218,12 @@ struct snd_soc_tplg_stream_caps {
  */
 struct snd_soc_tplg_stream {
        __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* Name of the stream */
        __le64 format;          /* SNDRV_PCM_FMTBIT_* */
        __le32 rate;            /* SNDRV_PCM_RATE_* */
        __le32 period_bytes;    /* size of period in bytes */
        __le32 buffer_bytes;    /* size of buffer in bytes */
        __le32 channels;        /* channels */
-       __le32 tdm_slot;        /* optional BE bitmask of supported TDM slots */
-       __le32 dai_fmt;         /* SND_SOC_DAIFMT_  */
-} __attribute__((packed));
-
-/*
- * Duplex stream configuration supported by SW/FW.
- */
-struct snd_soc_tplg_stream_config {
-       __le32 size;            /* in bytes of this structure */
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       struct snd_soc_tplg_stream playback;
-       struct snd_soc_tplg_stream capture;
 } __attribute__((packed));
 
 /*
@@ -366,11 +356,11 @@ struct snd_soc_tplg_dapm_widget {
        __le32 shift;           /* bits to shift */
        __le32 mask;            /* non-shifted mask */
        __le32 subseq;          /* sort within widget type */
-       __u32 invert;           /* invert the power bit */
-       __u32 ignore_suspend;   /* kept enabled over suspend */
-       __u16 event_flags;
-       __u16 event_type;
-       __u16 num_kcontrols;
+       __le32 invert;          /* invert the power bit */
+       __le32 ignore_suspend;  /* kept enabled over suspend */
+       __le16 event_flags;
+       __le16 event_type;
+       __le32 num_kcontrols;
        struct snd_soc_tplg_private priv;
        /*
         * kcontrols that relate to this widget
@@ -378,30 +368,46 @@ struct snd_soc_tplg_dapm_widget {
         */
 } __attribute__((packed));
 
-struct snd_soc_tplg_pcm_cfg_caps {
-       struct snd_soc_tplg_stream_caps caps;
-       struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
-       __le32 num_configs;     /* number of configs */
-} __attribute__((packed));
 
 /*
- * Describes SW/FW specific features of PCM or DAI link.
+ * Describes SW/FW specific features of PCM (FE DAI & DAI link).
  *
- * File block representation for PCM/DAI-Link :-
+ * File block representation for PCM :-
  * +-----------------------------------+-----+
  * | struct snd_soc_tplg_hdr           |  1  |
  * +-----------------------------------+-----+
- * | struct snd_soc_tplg_dapm_pcm_dai  |  N  |
+ * | struct snd_soc_tplg_pcm           |  N  |
  * +-----------------------------------+-----+
  */
-struct snd_soc_tplg_pcm_dai {
+struct snd_soc_tplg_pcm {
        __le32 size;            /* in bytes of this structure */
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       __le32 id;                      /* unique ID - used to match */
-       __le32 playback;                /* supports playback mode */
-       __le32 capture;                 /* supports capture mode */
-       __le32 compress;                /* 1 = compressed; 0 = PCM */
-       struct snd_soc_tplg_pcm_cfg_caps capconf[2];    /* capabilities and configs */
+       char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 pcm_id;          /* unique ID - used to match */
+       __le32 dai_id;          /* unique ID - used to match */
+       __le32 playback;        /* supports playback mode */
+       __le32 capture;         /* supports capture mode */
+       __le32 compress;        /* 1 = compressed; 0 = PCM */
+       struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */
+       __le32 num_streams;     /* number of streams */
+       struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */
 } __attribute__((packed));
 
+
+/*
+ * Describes the BE or CC link runtime supported configs or params
+ *
+ * File block representation for BE/CC link config :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_link_config   |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_link_config {
+       __le32 size;            /* in bytes of this structure */
+       __le32 id;              /* unique ID - used to match */
+       struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */
+       __le32 num_streams;     /* number of streams */
+} __attribute__((packed));
 #endif
index a45be6bdcf5bb88b2871a764e070ed9737818088..a82108e5d1c0ccfb627daf84ac80b153fe123f66 100644 (file)
@@ -100,9 +100,11 @@ enum {
        SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */
        SNDRV_HWDEP_IFACE_FW_BEBOB,     /* BridgeCo BeBoB based device */
        SNDRV_HWDEP_IFACE_FW_OXFW,      /* Oxford OXFW970/971 based device */
+       SNDRV_HWDEP_IFACE_FW_DIGI00X,   /* Digidesign Digi 002/003 family */
+       SNDRV_HWDEP_IFACE_FW_TASCAM,    /* TASCAM FireWire series */
 
        /* Don't forget to change the following: */
-       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_OXFW
+       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_TASCAM
 };
 
 struct snd_hwdep_info {
index ec1535bb6aedd043df4d5b4950805d8fc2aeaa05..5175e166987d173fb88ed1279614d89602ac22dc 100644 (file)
 
 #define EMU10K1_FX8010_PCM_COUNT               8
 
+/*
+ * Following definition is copied from linux/types.h to support compiling
+ * this header file in userspace since they are not generally available for
+ * uapi headers.
+ */
+#define __EMU10K1_DECLARE_BITMAP(name,bits) \
+       unsigned long name[(bits) / (sizeof(unsigned long) * 8)]
+
 /* instruction set */
 #define iMAC0   0x00   /* R = A + (X * Y >> 31)   ; saturation */
 #define iMAC1   0x01   /* R = A + (-X * Y >> 31)  ; saturation */
@@ -300,7 +308,7 @@ struct snd_emu10k1_fx8010_control_old_gpr {
 struct snd_emu10k1_fx8010_code {
        char name[128];
 
-       DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
+       __EMU10K1_DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
        __u32 __user *gpr_map;          /* initializers */
 
        unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */
@@ -313,11 +321,11 @@ struct snd_emu10k1_fx8010_code {
        unsigned int gpr_list_control_total; /* total count of GPR controls */
        struct snd_emu10k1_fx8010_control_gpr __user *gpr_list_controls; /* listed GPR controls */
 
-       DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
+       __EMU10K1_DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
        __u32 __user *tram_data_map;      /* data initializers */
        __u32 __user *tram_addr_map;      /* map initializers */
 
-       DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
+       __EMU10K1_DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
        __u32 __user *code;               /* one instruction - 64 bits */
 };
 
index 49122df3b56b31efcd7e37b739d67ccb13f02b00..db79a12fcc78db70d234b89d4b8bf6f573598224 100644 (file)
@@ -9,6 +9,7 @@
 #define SNDRV_FIREWIRE_EVENT_LOCK_STATUS       0x000010cc
 #define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e
 #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE      0x4e617475
+#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE   0x746e736c
 
 struct snd_firewire_event_common {
        unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -40,11 +41,17 @@ struct snd_firewire_event_efw_response {
        __be32 response[0];     /* some responses */
 };
 
+struct snd_firewire_event_digi00x_message {
+       unsigned int type;
+       __u32 message;  /* Digi00x-specific message */
+};
+
 union snd_firewire_event {
        struct snd_firewire_event_common            common;
        struct snd_firewire_event_lock_status       lock_status;
        struct snd_firewire_event_dice_notification dice_notification;
        struct snd_firewire_event_efw_response      efw_response;
+       struct snd_firewire_event_digi00x_message   digi00x_message;
 };
 
 
@@ -56,6 +63,8 @@ union snd_firewire_event {
 #define SNDRV_FIREWIRE_TYPE_FIREWORKS  2
 #define SNDRV_FIREWIRE_TYPE_BEBOB      3
 #define SNDRV_FIREWIRE_TYPE_OXFW       4
+#define SNDRV_FIREWIRE_TYPE_DIGI00X    5
+#define SNDRV_FIREWIRE_TYPE_TASCAM     6
 /* RME, MOTU, ... */
 
 struct snd_firewire_get_info {
index 5737332d38f2cea1f8c2f47f14e9d01282c87a52..c4db6f5b306ecb951cfa7cda58ab44add749147b 100644 (file)
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
 
 /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
 #define HDSPM_MAX_CHANNELS      64
@@ -46,15 +42,15 @@ enum hdspm_speed {
 /* -------------------- IOCTL Peak/RMS Meters -------------------- */
 
 struct hdspm_peak_rms {
-       uint32_t input_peaks[64];
-       uint32_t playback_peaks[64];
-       uint32_t output_peaks[64];
+       __u32 input_peaks[64];
+       __u32 playback_peaks[64];
+       __u32 output_peaks[64];
 
-       uint64_t input_rms[64];
-       uint64_t playback_rms[64];
-       uint64_t output_rms[64];
+       __u64 input_rms[64];
+       __u64 playback_rms[64];
+       __u64 output_rms[64];
 
-       uint8_t speed; /* enum {ss, ds, qs} */
+       __u8 speed; /* enum {ss, ds, qs} */
        int status2;
 };
 
@@ -155,21 +151,21 @@ enum hdspm_syncsource {
 };
 
 struct hdspm_status {
-       uint8_t card_type; /* enum hdspm_io_type */
+       __u8 card_type; /* enum hdspm_io_type */
        enum hdspm_syncsource autosync_source;
 
-       uint64_t card_clock;
-       uint32_t master_period;
+       __u64 card_clock;
+       __u32 master_period;
 
        union {
                struct {
-                       uint8_t sync_wc; /* enum hdspm_sync */
-                       uint8_t sync_madi; /* enum hdspm_sync */
-                       uint8_t sync_tco; /* enum hdspm_sync */
-                       uint8_t sync_in; /* enum hdspm_sync */
-                       uint8_t madi_input; /* enum hdspm_madi_input */
-                       uint8_t channel_format; /* enum hdspm_madi_channel_format */
-                       uint8_t frame_format; /* enum hdspm_madi_frame_format */
+                       __u8 sync_wc; /* enum hdspm_sync */
+                       __u8 sync_madi; /* enum hdspm_sync */
+                       __u8 sync_tco; /* enum hdspm_sync */
+                       __u8 sync_in; /* enum hdspm_sync */
+                       __u8 madi_input; /* enum hdspm_madi_input */
+                       __u8 channel_format; /* enum hdspm_madi_channel_format */
+                       __u8 frame_format; /* enum hdspm_madi_frame_format */
                } madi;
        } card_specific;
 };
@@ -184,7 +180,7 @@ struct hdspm_status {
 #define HDSPM_ADDON_TCO 1
 
 struct hdspm_version {
-       uint8_t card_type; /* enum hdspm_io_type */
+       __u8 card_type; /* enum hdspm_io_type */
        char cardname[20];
        unsigned int serial;
        unsigned short firmware_rev;
index 1153c43428f3b51d43aba2e8df21950d9029ab04..8d6363f42169c62c61e9a035d615a89966135b0f 100644 (file)
@@ -635,6 +635,13 @@ config TRACE_ENUM_MAP_FILE
 
        If unsure, say N
 
+config TRACING_EVENTS_GPIO
+       bool "Trace gpio events"
+       depends on GPIOLIB
+       default y
+       help
+         Enable tracing events for gpio subsystem
+
 endif # FTRACE
 
 endif # TRACING_SUPPORT
index e3a26188b95e6fbc863a98e4d1df25df5b5ddaee..a990824c86044779c089156daea170412cc84e8e 100644 (file)
@@ -103,7 +103,7 @@ record_it:
                memcpy((void *) t + sizeof(*t), data, len);
 
                if (blk_tracer)
-                       trace_buffer_unlock_commit(buffer, event, 0, pc);
+                       trace_buffer_unlock_commit(blk_tr, buffer, event, 0, pc);
        }
 }
 
@@ -278,7 +278,7 @@ record_it:
                        memcpy((void *) t + sizeof(*t), pdu_data, pdu_len);
 
                if (blk_tracer) {
-                       trace_buffer_unlock_commit(buffer, event, 0, pc);
+                       trace_buffer_unlock_commit(blk_tr, buffer, event, 0, pc);
                        return;
                }
        }
@@ -1340,6 +1340,7 @@ static const struct {
 static enum print_line_t print_one_line(struct trace_iterator *iter,
                                        bool classic)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        const struct blk_io_trace *t;
        u16 what;
@@ -1348,7 +1349,7 @@ static enum print_line_t print_one_line(struct trace_iterator *iter,
 
        t          = te_blk_io_trace(iter->ent);
        what       = t->action & ((1 << BLK_TC_SHIFT) - 1);
-       long_act   = !!(trace_flags & TRACE_ITER_VERBOSE);
+       long_act   = !!(tr->trace_flags & TRACE_ITER_VERBOSE);
        log_action = classic ? &blk_log_action_classic : &blk_log_action;
 
        if (t->action == BLK_TN_MESSAGE) {
@@ -1410,9 +1411,9 @@ blk_tracer_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
        /* don't output context-info for blk_classic output */
        if (bit == TRACE_BLK_OPT_CLASSIC) {
                if (set)
-                       trace_flags &= ~TRACE_ITER_CONTEXT_INFO;
+                       tr->trace_flags &= ~TRACE_ITER_CONTEXT_INFO;
                else
-                       trace_flags |= TRACE_ITER_CONTEXT_INFO;
+                       tr->trace_flags |= TRACE_ITER_CONTEXT_INFO;
        }
        return 0;
 }
index 00611e95a8ee00bb91e7ccbd41c3ebcbc580e4f8..3f743b147247034e6a794f7cf47176a2c6a44ece 100644 (file)
@@ -243,6 +243,11 @@ static void ftrace_sync_ipi(void *data)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 static void update_function_graph_func(void);
+
+/* Both enabled by default (can be cleared by function_graph tracer flags */
+static bool fgraph_sleep_time = true;
+static bool fgraph_graph_time = true;
+
 #else
 static inline void update_function_graph_func(void) { }
 #endif
@@ -917,7 +922,7 @@ static void profile_graph_return(struct ftrace_graph_ret *trace)
 
        calltime = trace->rettime - trace->calltime;
 
-       if (!(trace_flags & TRACE_ITER_GRAPH_TIME)) {
+       if (!fgraph_graph_time) {
                int index;
 
                index = trace->depth;
@@ -3420,27 +3425,35 @@ ftrace_notrace_open(struct inode *inode, struct file *file)
                                 inode, file);
 }
 
-static int ftrace_match(char *str, char *regex, int len, int type)
+/* Type for quick search ftrace basic regexes (globs) from filter_parse_regex */
+struct ftrace_glob {
+       char *search;
+       unsigned len;
+       int type;
+};
+
+static int ftrace_match(char *str, struct ftrace_glob *g)
 {
        int matched = 0;
        int slen;
 
-       switch (type) {
+       switch (g->type) {
        case MATCH_FULL:
-               if (strcmp(str, regex) == 0)
+               if (strcmp(str, g->search) == 0)
                        matched = 1;
                break;
        case MATCH_FRONT_ONLY:
-               if (strncmp(str, regex, len) == 0)
+               if (strncmp(str, g->search, g->len) == 0)
                        matched = 1;
                break;
        case MATCH_MIDDLE_ONLY:
-               if (strstr(str, regex))
+               if (strstr(str, g->search))
                        matched = 1;
                break;
        case MATCH_END_ONLY:
                slen = strlen(str);
-               if (slen >= len && memcmp(str + slen - len, regex, len) == 0)
+               if (slen >= g->len &&
+                   memcmp(str + slen - g->len, g->search, g->len) == 0)
                        matched = 1;
                break;
        }
@@ -3449,13 +3462,13 @@ static int ftrace_match(char *str, char *regex, int len, int type)
 }
 
 static int
-enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int not)
+enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter)
 {
        struct ftrace_func_entry *entry;
        int ret = 0;
 
        entry = ftrace_lookup_ip(hash, rec->ip);
-       if (not) {
+       if (clear_filter) {
                /* Do nothing if it doesn't exist */
                if (!entry)
                        return 0;
@@ -3472,42 +3485,68 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int not)
 }
 
 static int
-ftrace_match_record(struct dyn_ftrace *rec, char *mod,
-                   char *regex, int len, int type)
+ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g,
+               struct ftrace_glob *mod_g, int exclude_mod)
 {
        char str[KSYM_SYMBOL_LEN];
        char *modname;
 
        kallsyms_lookup(rec->ip, NULL, NULL, &modname, str);
 
-       if (mod) {
-               /* module lookup requires matching the module */
-               if (!modname || strcmp(modname, mod))
+       if (mod_g) {
+               int mod_matches = (modname) ? ftrace_match(modname, mod_g) : 0;
+
+               /* blank module name to match all modules */
+               if (!mod_g->len) {
+                       /* blank module globbing: modname xor exclude_mod */
+                       if ((!exclude_mod) != (!modname))
+                               goto func_match;
+                       return 0;
+               }
+
+               /* not matching the module */
+               if (!modname || !mod_matches) {
+                       if (exclude_mod)
+                               goto func_match;
+                       else
+                               return 0;
+               }
+
+               if (mod_matches && exclude_mod)
                        return 0;
 
+func_match:
                /* blank search means to match all funcs in the mod */
-               if (!len)
+               if (!func_g->len)
                        return 1;
        }
 
-       return ftrace_match(str, regex, len, type);
+       return ftrace_match(str, func_g);
 }
 
 static int
-match_records(struct ftrace_hash *hash, char *buff,
-             int len, char *mod, int not)
+match_records(struct ftrace_hash *hash, char *func, int len, char *mod)
 {
-       unsigned search_len = 0;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
-       int type = MATCH_FULL;
-       char *search = buff;
+       struct ftrace_glob func_g = { .type = MATCH_FULL };
+       struct ftrace_glob mod_g = { .type = MATCH_FULL };
+       struct ftrace_glob *mod_match = (mod) ? &mod_g : NULL;
+       int exclude_mod = 0;
        int found = 0;
        int ret;
+       int clear_filter;
+
+       if (func) {
+               func_g.type = filter_parse_regex(func, len, &func_g.search,
+                                                &clear_filter);
+               func_g.len = strlen(func_g.search);
+       }
 
-       if (len) {
-               type = filter_parse_regex(buff, len, &search, &not);
-               search_len = strlen(search);
+       if (mod) {
+               mod_g.type = filter_parse_regex(mod, strlen(mod),
+                               &mod_g.search, &exclude_mod);
+               mod_g.len = strlen(mod_g.search);
        }
 
        mutex_lock(&ftrace_lock);
@@ -3516,8 +3555,8 @@ 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 (ftrace_match_record(rec, &func_g, mod_match, exclude_mod)) {
+                       ret = enter_record(hash, rec, clear_filter);
                        if (ret < 0) {
                                found = ret;
                                goto out_unlock;
@@ -3534,26 +3573,9 @@ match_records(struct ftrace_hash *hash, char *buff,
 static int
 ftrace_match_records(struct ftrace_hash *hash, char *buff, int len)
 {
-       return match_records(hash, buff, len, NULL, 0);
+       return match_records(hash, buff, len, NULL);
 }
 
-static int
-ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod)
-{
-       int not = 0;
-
-       /* blank or '*' mean the same */
-       if (strcmp(buff, "*") == 0)
-               buff[0] = 0;
-
-       /* handle the case of 'dont filter this module' */
-       if (strcmp(buff, "!") == 0 || strcmp(buff, "!*") == 0) {
-               buff[0] = 0;
-               not = 1;
-       }
-
-       return match_records(hash, buff, strlen(buff), mod, not);
-}
 
 /*
  * We register the module command as a template to show others how
@@ -3562,10 +3584,9 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod)
 
 static int
 ftrace_mod_callback(struct ftrace_hash *hash,
-                   char *func, char *cmd, char *param, int enable)
+                   char *func, char *cmd, char *module, int enable)
 {
-       char *mod;
-       int ret = -EINVAL;
+       int ret;
 
        /*
         * cmd == 'mod' because we only registered this func
@@ -3574,21 +3595,11 @@ ftrace_mod_callback(struct ftrace_hash *hash,
         * you can tell which command was used by the cmd
         * parameter.
         */
-
-       /* we must have a module name */
-       if (!param)
-               return ret;
-
-       mod = strsep(&param, ":");
-       if (!strlen(mod))
-               return ret;
-
-       ret = ftrace_match_module_records(hash, func, mod);
+       ret = match_records(hash, func, strlen(func), module);
        if (!ret)
-               ret = -EINVAL;
+               return -EINVAL;
        if (ret < 0)
                return ret;
-
        return 0;
 }
 
@@ -3699,19 +3710,20 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 {
        struct ftrace_ops_hash old_hash_ops;
        struct ftrace_func_probe *entry;
+       struct ftrace_glob func_g;
        struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
        struct ftrace_hash *old_hash = *orig_hash;
        struct ftrace_hash *hash;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
-       int type, len, not;
+       int not;
        unsigned long key;
        int count = 0;
-       char *search;
        int ret;
 
-       type = filter_parse_regex(glob, strlen(glob), &search, &not);
-       len = strlen(search);
+       func_g.type = filter_parse_regex(glob, strlen(glob),
+                       &func_g.search, &not);
+       func_g.len = strlen(func_g.search);
 
        /* we do not support '!' for function probes */
        if (WARN_ON(not))
@@ -3738,7 +3750,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        do_for_each_ftrace_rec(pg, rec) {
 
-               if (!ftrace_match_record(rec, NULL, search, len, type))
+               if (!ftrace_match_record(rec, &func_g, NULL, 0))
                        continue;
 
                entry = kmalloc(sizeof(*entry), GFP_KERNEL);
@@ -3811,24 +3823,24 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        struct ftrace_func_entry *rec_entry;
        struct ftrace_func_probe *entry;
        struct ftrace_func_probe *p;
+       struct ftrace_glob func_g;
        struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
        struct ftrace_hash *old_hash = *orig_hash;
        struct list_head free_list;
        struct ftrace_hash *hash;
        struct hlist_node *tmp;
        char str[KSYM_SYMBOL_LEN];
-       int type = MATCH_FULL;
-       int i, len = 0;
-       char *search;
-       int ret;
+       int i, ret;
 
        if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
-               glob = NULL;
+               func_g.search = NULL;
        else if (glob) {
                int not;
 
-               type = filter_parse_regex(glob, strlen(glob), &search, &not);
-               len = strlen(search);
+               func_g.type = filter_parse_regex(glob, strlen(glob),
+                                                &func_g.search, &not);
+               func_g.len = strlen(func_g.search);
+               func_g.search = glob;
 
                /* we do not support '!' for function probes */
                if (WARN_ON(not))
@@ -3857,10 +3869,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                                continue;
 
                        /* do this last, since it is the most expensive */
-                       if (glob) {
+                       if (func_g.search) {
                                kallsyms_lookup(entry->ip, NULL, NULL,
                                                NULL, str);
-                               if (!ftrace_match(str, glob, len, type))
+                               if (!ftrace_match(str, &func_g))
                                        continue;
                        }
 
@@ -3889,7 +3901,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                ftrace_free_entry(entry);
        }
        mutex_unlock(&ftrace_lock);
-               
+
  out_unlock:
        mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
        free_ftrace_hash(hash);
@@ -4605,21 +4617,21 @@ ftrace_graph_release(struct inode *inode, struct file *file)
 static int
 ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer)
 {
+       struct ftrace_glob func_g;
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
-       int search_len;
        int fail = 1;
-       int type, not;
-       char *search;
+       int not;
        bool exists;
        int i;
 
        /* decode regex */
-       type = filter_parse_regex(buffer, strlen(buffer), &search, &not);
+       func_g.type = filter_parse_regex(buffer, strlen(buffer),
+                                        &func_g.search, &not);
        if (!not && *idx >= size)
                return -EBUSY;
 
-       search_len = strlen(search);
+       func_g.len = strlen(func_g.search);
 
        mutex_lock(&ftrace_lock);
 
@@ -4630,7 +4642,7 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer)
 
        do_for_each_ftrace_rec(pg, rec) {
 
-               if (ftrace_match_record(rec, NULL, search, search_len, type)) {
+               if (ftrace_match_record(rec, &func_g, NULL, 0)) {
                        /* if it is in the array */
                        exists = false;
                        for (i = 0; i < *idx; i++) {
@@ -4783,17 +4795,6 @@ static int ftrace_cmp_ips(const void *a, const void *b)
        return 0;
 }
 
-static void ftrace_swap_ips(void *a, void *b, int size)
-{
-       unsigned long *ipa = a;
-       unsigned long *ipb = b;
-       unsigned long t;
-
-       t = *ipa;
-       *ipa = *ipb;
-       *ipb = t;
-}
-
 static int ftrace_process_locs(struct module *mod,
                               unsigned long *start,
                               unsigned long *end)
@@ -4813,7 +4814,7 @@ static int ftrace_process_locs(struct module *mod,
                return 0;
 
        sort(start, count, sizeof(*start),
-            ftrace_cmp_ips, ftrace_swap_ips);
+            ftrace_cmp_ips, NULL);
 
        start_pg = ftrace_allocate_pages(count);
        if (!start_pg)
@@ -5639,6 +5640,16 @@ static struct ftrace_ops graph_ops = {
        ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
 };
 
+void ftrace_graph_sleep_time_control(bool enable)
+{
+       fgraph_sleep_time = enable;
+}
+
+void ftrace_graph_graph_time_control(bool enable)
+{
+       fgraph_graph_time = enable;
+}
+
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
 {
        return 0;
@@ -5707,7 +5718,7 @@ ftrace_graph_probe_sched_switch(void *ignore, bool preempt,
         * Does the user want to count the time a function was asleep.
         * If so, do not update the time stamps.
         */
-       if (trace_flags & TRACE_ITER_SLEEP_TIME)
+       if (fgraph_sleep_time)
                return;
 
        timestamp = trace_clock_local();
index fc347f8b1bca24debb823cdeca09424368c16e2e..75f1d05ea82dcce04e9f6a581f26969e503dc773 100644 (file)
@@ -829,7 +829,7 @@ rb_is_head_page(struct ring_buffer_per_cpu *cpu_buffer,
  * writer is ever on it, the previous pointer never points
  * back to the reader page.
  */
-static int rb_is_reader_page(struct buffer_page *page)
+static bool rb_is_reader_page(struct buffer_page *page)
 {
        struct list_head *list = page->list.prev;
 
@@ -2270,7 +2270,7 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta)
        return skip_time_extend(event);
 }
 
-static inline int rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer,
+static inline bool rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer,
                                     struct ring_buffer_event *event);
 
 /**
@@ -2498,7 +2498,7 @@ static inline void rb_event_discard(struct ring_buffer_event *event)
                event->time_delta = 1;
 }
 
-static inline int
+static inline bool
 rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer,
                   struct ring_buffer_event *event)
 {
@@ -3039,7 +3039,7 @@ int ring_buffer_write(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(ring_buffer_write);
 
-static int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
+static bool rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
 {
        struct buffer_page *reader = cpu_buffer->reader_page;
        struct buffer_page *head = rb_set_head_page(cpu_buffer);
@@ -3047,7 +3047,7 @@ static int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
 
        /* In case of error, head will be NULL */
        if (unlikely(!head))
-               return 1;
+               return true;
 
        return reader->read == rb_page_commit(reader) &&
                (commit == reader ||
@@ -4267,7 +4267,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_reset);
  * rind_buffer_empty - is the ring buffer empty?
  * @buffer: The ring buffer to test
  */
-int ring_buffer_empty(struct ring_buffer *buffer)
+bool ring_buffer_empty(struct ring_buffer *buffer)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
        unsigned long flags;
@@ -4285,10 +4285,10 @@ int ring_buffer_empty(struct ring_buffer *buffer)
                local_irq_restore(flags);
 
                if (!ret)
-                       return 0;
+                       return false;
        }
 
-       return 1;
+       return true;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_empty);
 
@@ -4297,7 +4297,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_empty);
  * @buffer: The ring buffer
  * @cpu: The CPU buffer to test
  */
-int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu)
+bool ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
        unsigned long flags;
@@ -4305,7 +4305,7 @@ int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu)
        int ret;
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
-               return 1;
+               return true;
 
        cpu_buffer = buffer->buffers[cpu];
        local_irq_save(flags);
index a1503a027ee28e037b39aed56a80b45aed48fbf1..6df9a83e20d7eb360a6e58eb2599a959326c6bcc 100644 (file)
@@ -24,8 +24,8 @@ struct rb_page {
 static int wakeup_interval = 100;
 
 static int reader_finish;
-static struct completion read_start;
-static struct completion read_done;
+static DECLARE_COMPLETION(read_start);
+static DECLARE_COMPLETION(read_done);
 
 static struct ring_buffer *buffer;
 static struct task_struct *producer;
@@ -60,12 +60,12 @@ MODULE_PARM_DESC(consumer_fifo, "fifo prio for consumer");
 
 static int read_events;
 
-static int kill_test;
+static int test_error;
 
-#define KILL_TEST()                            \
+#define TEST_ERROR()                           \
        do {                                    \
-               if (!kill_test) {               \
-                       kill_test = 1;          \
+               if (!test_error) {              \
+                       test_error = 1;         \
                        WARN_ON(1);             \
                }                               \
        } while (0)
@@ -75,6 +75,11 @@ enum event_status {
        EVENT_DROPPED,
 };
 
+static bool break_test(void)
+{
+       return test_error || kthread_should_stop();
+}
+
 static enum event_status read_event(int cpu)
 {
        struct ring_buffer_event *event;
@@ -87,7 +92,7 @@ static enum event_status read_event(int cpu)
 
        entry = ring_buffer_event_data(event);
        if (*entry != cpu) {
-               KILL_TEST();
+               TEST_ERROR();
                return EVENT_DROPPED;
        }
 
@@ -115,10 +120,10 @@ static enum event_status read_page(int cpu)
                rpage = bpage;
                /* The commit may have missed event flags set, clear them */
                commit = local_read(&rpage->commit) & 0xfffff;
-               for (i = 0; i < commit && !kill_test; i += inc) {
+               for (i = 0; i < commit && !test_error ; i += inc) {
 
                        if (i >= (PAGE_SIZE - offsetof(struct rb_page, data))) {
-                               KILL_TEST();
+                               TEST_ERROR();
                                break;
                        }
 
@@ -128,7 +133,7 @@ static enum event_status read_page(int cpu)
                        case RINGBUF_TYPE_PADDING:
                                /* failed writes may be discarded events */
                                if (!event->time_delta)
-                                       KILL_TEST();
+                                       TEST_ERROR();
                                inc = event->array[0] + 4;
                                break;
                        case RINGBUF_TYPE_TIME_EXTEND:
@@ -137,12 +142,12 @@ static enum event_status read_page(int cpu)
                        case 0:
                                entry = ring_buffer_event_data(event);
                                if (*entry != cpu) {
-                                       KILL_TEST();
+                                       TEST_ERROR();
                                        break;
                                }
                                read++;
                                if (!event->array[0]) {
-                                       KILL_TEST();
+                                       TEST_ERROR();
                                        break;
                                }
                                inc = event->array[0] + 4;
@@ -150,17 +155,17 @@ static enum event_status read_page(int cpu)
                        default:
                                entry = ring_buffer_event_data(event);
                                if (*entry != cpu) {
-                                       KILL_TEST();
+                                       TEST_ERROR();
                                        break;
                                }
                                read++;
                                inc = ((event->type_len + 1) * 4);
                        }
-                       if (kill_test)
+                       if (test_error)
                                break;
 
                        if (inc <= 0) {
-                               KILL_TEST();
+                               TEST_ERROR();
                                break;
                        }
                }
@@ -178,10 +183,14 @@ static void ring_buffer_consumer(void)
        read_events ^= 1;
 
        read = 0;
-       while (!reader_finish && !kill_test) {
-               int found;
+       /*
+        * Continue running until the producer specifically asks to stop
+        * and is ready for the completion.
+        */
+       while (!READ_ONCE(reader_finish)) {
+               int found = 1;
 
-               do {
+               while (found && !test_error) {
                        int cpu;
 
                        found = 0;
@@ -193,19 +202,25 @@ static void ring_buffer_consumer(void)
                                else
                                        stat = read_page(cpu);
 
-                               if (kill_test)
+                               if (test_error)
                                        break;
+
                                if (stat == EVENT_FOUND)
                                        found = 1;
+
                        }
-               } while (found && !kill_test);
+               }
 
+               /* Wait till the producer wakes us up when there is more data
+                * available or when the producer wants us to finish reading.
+                */
                set_current_state(TASK_INTERRUPTIBLE);
                if (reader_finish)
                        break;
 
                schedule();
        }
+       __set_current_state(TASK_RUNNING);
        reader_finish = 0;
        complete(&read_done);
 }
@@ -263,10 +278,7 @@ static void ring_buffer_producer(void)
                if (cnt % wakeup_interval)
                        cond_resched();
 #endif
-               if (kthread_should_stop())
-                       kill_test = 1;
-
-       } while (ktime_before(end_time, timeout) && !kill_test);
+       } while (ktime_before(end_time, timeout) && !break_test());
        trace_printk("End ring buffer hammer\n");
 
        if (consumer) {
@@ -276,8 +288,6 @@ static void ring_buffer_producer(void)
                /* the completions must be visible before the finish var */
                smp_wmb();
                reader_finish = 1;
-               /* finish var visible before waking up the consumer */
-               smp_wmb();
                wake_up_process(consumer);
                wait_for_completion(&read_done);
        }
@@ -287,7 +297,7 @@ static void ring_buffer_producer(void)
        entries = ring_buffer_entries(buffer);
        overruns = ring_buffer_overruns(buffer);
 
-       if (kill_test && !kthread_should_stop())
+       if (test_error)
                trace_printk("ERROR!\n");
 
        if (!disable_reader) {
@@ -368,15 +378,14 @@ static void wait_to_die(void)
 
 static int ring_buffer_consumer_thread(void *arg)
 {
-       while (!kthread_should_stop() && !kill_test) {
+       while (!break_test()) {
                complete(&read_start);
 
                ring_buffer_consumer();
 
                set_current_state(TASK_INTERRUPTIBLE);
-               if (kthread_should_stop() || kill_test)
+               if (break_test())
                        break;
-
                schedule();
        }
        __set_current_state(TASK_RUNNING);
@@ -389,27 +398,27 @@ static int ring_buffer_consumer_thread(void *arg)
 
 static int ring_buffer_producer_thread(void *arg)
 {
-       init_completion(&read_start);
-
-       while (!kthread_should_stop() && !kill_test) {
+       while (!break_test()) {
                ring_buffer_reset(buffer);
 
                if (consumer) {
-                       smp_wmb();
                        wake_up_process(consumer);
                        wait_for_completion(&read_start);
                }
 
                ring_buffer_producer();
-               if (kill_test)
+               if (break_test())
                        goto out_kill;
 
                trace_printk("Sleeping for 10 secs\n");
                set_current_state(TASK_INTERRUPTIBLE);
+               if (break_test())
+                       goto out_kill;
                schedule_timeout(HZ * SLEEP_TIME);
        }
 
 out_kill:
+       __set_current_state(TASK_RUNNING);
        if (!kthread_should_stop())
                wait_to_die();
 
index 6e79408674aaa15e7f5be7da0e86488599fdfa0f..2198a630ef5826a30e51a2974d472b078273f80c 100644 (file)
@@ -214,12 +214,10 @@ __setup("alloc_snapshot", boot_alloc_snapshot);
 
 
 static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata;
-static char *trace_boot_options __initdata;
 
 static int __init set_trace_boot_options(char *str)
 {
        strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
-       trace_boot_options = trace_boot_options_buf;
        return 0;
 }
 __setup("trace_options=", set_trace_boot_options);
@@ -250,6 +248,19 @@ unsigned long long ns2usecs(cycle_t nsec)
        return nsec;
 }
 
+/* trace_flags holds trace_options default values */
+#define TRACE_DEFAULT_FLAGS                                            \
+       (FUNCTION_DEFAULT_FLAGS |                                       \
+        TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |                  \
+        TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO |                \
+        TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |                 \
+        TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS)
+
+/* trace_options that are only supported by global_trace */
+#define TOP_LEVEL_TRACE_FLAGS (TRACE_ITER_PRINTK |                     \
+              TRACE_ITER_PRINTK_MSGONLY | TRACE_ITER_RECORD_CMD)
+
+
 /*
  * The global_trace is the descriptor that holds the tracing
  * buffers for the live tracing. For each CPU, it contains
@@ -262,7 +273,9 @@ unsigned long long ns2usecs(cycle_t nsec)
  * pages for the buffer for that CPU. Each CPU has the same number
  * of pages allocated for its buffer.
  */
-static struct trace_array      global_trace;
+static struct trace_array global_trace = {
+       .trace_flags = TRACE_DEFAULT_FLAGS,
+};
 
 LIST_HEAD(ftrace_trace_arrays);
 
@@ -468,11 +481,29 @@ static inline void trace_access_lock_init(void)
 
 #endif
 
-/* trace_flags holds trace_options default values */
-unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
-       TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
-       TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
-       TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;
+#ifdef CONFIG_STACKTRACE
+static void __ftrace_trace_stack(struct ring_buffer *buffer,
+                                unsigned long flags,
+                                int skip, int pc, struct pt_regs *regs);
+static inline void ftrace_trace_stack(struct trace_array *tr,
+                                     struct ring_buffer *buffer,
+                                     unsigned long flags,
+                                     int skip, int pc, struct pt_regs *regs);
+
+#else
+static inline void __ftrace_trace_stack(struct ring_buffer *buffer,
+                                       unsigned long flags,
+                                       int skip, int pc, struct pt_regs *regs)
+{
+}
+static inline void ftrace_trace_stack(struct trace_array *tr,
+                                     struct ring_buffer *buffer,
+                                     unsigned long flags,
+                                     int skip, int pc, struct pt_regs *regs)
+{
+}
+
+#endif
 
 static void tracer_tracing_on(struct trace_array *tr)
 {
@@ -518,7 +549,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)
        int alloc;
        int pc;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
        pc = preempt_count();
@@ -548,7 +579,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)
                entry->buf[size] = '\0';
 
        __buffer_unlock_commit(buffer, event);
-       ftrace_trace_stack(buffer, irq_flags, 4, pc);
+       ftrace_trace_stack(&global_trace, buffer, irq_flags, 4, pc, NULL);
 
        return size;
 }
@@ -568,7 +599,7 @@ int __trace_bputs(unsigned long ip, const char *str)
        int size = sizeof(struct bputs_entry);
        int pc;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
        pc = preempt_count();
@@ -588,7 +619,7 @@ int __trace_bputs(unsigned long ip, const char *str)
        entry->str                      = str;
 
        __buffer_unlock_commit(buffer, event);
-       ftrace_trace_stack(buffer, irq_flags, 4, pc);
+       ftrace_trace_stack(&global_trace, buffer, irq_flags, 4, pc, NULL);
 
        return 1;
 }
@@ -834,34 +865,18 @@ unsigned long nsecs_to_usecs(unsigned long nsecs)
        return nsecs / 1000;
 }
 
+/*
+ * TRACE_FLAGS is defined as a tuple matching bit masks with strings.
+ * It uses C(a, b) where 'a' is the enum name and 'b' is the string that
+ * matches it. By defining "C(a, b) b", TRACE_FLAGS becomes a list
+ * of strings in the order that the enums were defined.
+ */
+#undef C
+#define C(a, b) b
+
 /* These must match the bit postions in trace_iterator_flags */
 static const char *trace_options[] = {
-       "print-parent",
-       "sym-offset",
-       "sym-addr",
-       "verbose",
-       "raw",
-       "hex",
-       "bin",
-       "block",
-       "stacktrace",
-       "trace_printk",
-       "ftrace_preempt",
-       "branch",
-       "annotate",
-       "userstacktrace",
-       "sym-userobj",
-       "printk-msg-only",
-       "context-info",
-       "latency-format",
-       "sleep-time",
-       "graph-time",
-       "record-cmd",
-       "overwrite",
-       "disable_on_free",
-       "irq-info",
-       "markers",
-       "function-trace",
+       TRACE_FLAGS
        NULL
 };
 
@@ -1204,13 +1219,17 @@ static inline int run_tracer_selftest(struct tracer *type)
 }
 #endif /* CONFIG_FTRACE_STARTUP_TEST */
 
+static void add_tracer_options(struct trace_array *tr, struct tracer *t);
+
+static void __init apply_trace_boot_options(void);
+
 /**
  * register_tracer - register a tracer with the ftrace system.
  * @type - the plugin for the tracer
  *
  * Register a new plugin tracer.
  */
-int register_tracer(struct tracer *type)
+int __init register_tracer(struct tracer *type)
 {
        struct tracer *t;
        int ret = 0;
@@ -1253,6 +1272,7 @@ int register_tracer(struct tracer *type)
 
        type->next = trace_types;
        trace_types = type;
+       add_tracer_options(&global_trace, type);
 
  out:
        tracing_selftest_running = false;
@@ -1268,6 +1288,9 @@ int register_tracer(struct tracer *type)
        /* Do we want this tracer to start on bootup? */
        tracing_set_tracer(&global_trace, type->name);
        default_bootup_tracer = NULL;
+
+       apply_trace_boot_options();
+
        /* disable other selftests, since this will break it. */
        tracing_selftest_disabled = true;
 #ifdef CONFIG_FTRACE_STARTUP_TEST
@@ -1671,23 +1694,16 @@ __buffer_unlock_commit(struct ring_buffer *buffer, struct ring_buffer_event *eve
        ring_buffer_unlock_commit(buffer, event);
 }
 
-static inline void
-__trace_buffer_unlock_commit(struct ring_buffer *buffer,
-                            struct ring_buffer_event *event,
-                            unsigned long flags, int pc)
+void trace_buffer_unlock_commit(struct trace_array *tr,
+                               struct ring_buffer *buffer,
+                               struct ring_buffer_event *event,
+                               unsigned long flags, int pc)
 {
        __buffer_unlock_commit(buffer, event);
 
-       ftrace_trace_stack(buffer, flags, 6, pc);
+       ftrace_trace_stack(tr, buffer, flags, 6, pc, NULL);
        ftrace_trace_userstack(buffer, flags, pc);
 }
-
-void trace_buffer_unlock_commit(struct ring_buffer *buffer,
-                               struct ring_buffer_event *event,
-                               unsigned long flags, int pc)
-{
-       __trace_buffer_unlock_commit(buffer, event, flags, pc);
-}
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
 static struct ring_buffer *temp_buffer;
@@ -1729,22 +1745,15 @@ trace_current_buffer_lock_reserve(struct ring_buffer **current_rb,
 }
 EXPORT_SYMBOL_GPL(trace_current_buffer_lock_reserve);
 
-void trace_current_buffer_unlock_commit(struct ring_buffer *buffer,
-                                       struct ring_buffer_event *event,
-                                       unsigned long flags, int pc)
-{
-       __trace_buffer_unlock_commit(buffer, event, flags, pc);
-}
-EXPORT_SYMBOL_GPL(trace_current_buffer_unlock_commit);
-
-void trace_buffer_unlock_commit_regs(struct ring_buffer *buffer,
+void trace_buffer_unlock_commit_regs(struct trace_array *tr,
+                                    struct ring_buffer *buffer,
                                     struct ring_buffer_event *event,
                                     unsigned long flags, int pc,
                                     struct pt_regs *regs)
 {
        __buffer_unlock_commit(buffer, event);
 
-       ftrace_trace_stack_regs(buffer, flags, 0, pc, regs);
+       ftrace_trace_stack(tr, buffer, flags, 6, pc, regs);
        ftrace_trace_userstack(buffer, flags, pc);
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit_regs);
@@ -1873,24 +1882,17 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
 
 }
 
-void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags,
-                            int skip, int pc, struct pt_regs *regs)
+static inline void ftrace_trace_stack(struct trace_array *tr,
+                                     struct ring_buffer *buffer,
+                                     unsigned long flags,
+                                     int skip, int pc, struct pt_regs *regs)
 {
-       if (!(trace_flags & TRACE_ITER_STACKTRACE))
+       if (!(tr->trace_flags & TRACE_ITER_STACKTRACE))
                return;
 
        __ftrace_trace_stack(buffer, flags, skip, pc, regs);
 }
 
-void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
-                       int skip, int pc)
-{
-       if (!(trace_flags & TRACE_ITER_STACKTRACE))
-               return;
-
-       __ftrace_trace_stack(buffer, flags, skip, pc, NULL);
-}
-
 void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
                   int pc)
 {
@@ -1929,7 +1931,7 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc)
        struct userstack_entry *entry;
        struct stack_trace trace;
 
-       if (!(trace_flags & TRACE_ITER_USERSTACKTRACE))
+       if (!(global_trace.trace_flags & TRACE_ITER_USERSTACKTRACE))
                return;
 
        /*
@@ -2173,7 +2175,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
        memcpy(entry->buf, tbuffer, sizeof(u32) * len);
        if (!call_filter_check_discard(call, entry, buffer, event)) {
                __buffer_unlock_commit(buffer, event);
-               ftrace_trace_stack(buffer, flags, 6, pc);
+               ftrace_trace_stack(tr, buffer, flags, 6, pc, NULL);
        }
 
 out:
@@ -2225,7 +2227,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,
        memcpy(&entry->buf, tbuffer, len + 1);
        if (!call_filter_check_discard(call, entry, buffer, event)) {
                __buffer_unlock_commit(buffer, event);
-               ftrace_trace_stack(buffer, flags, 6, pc);
+               ftrace_trace_stack(&global_trace, buffer, flags, 6, pc, NULL);
        }
  out:
        preempt_enable_notrace();
@@ -2246,7 +2248,7 @@ int trace_array_printk(struct trace_array *tr,
        int ret;
        va_list ap;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
        va_start(ap, fmt);
@@ -2261,7 +2263,7 @@ int trace_array_printk_buf(struct ring_buffer *buffer,
        int ret;
        va_list ap;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
        va_start(ap, fmt);
@@ -2602,7 +2604,7 @@ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file
 void
 print_trace_header(struct seq_file *m, struct trace_iterator *iter)
 {
-       unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
+       unsigned long sym_flags = (global_trace.trace_flags & TRACE_ITER_SYM_MASK);
        struct trace_buffer *buf = iter->trace_buffer;
        struct trace_array_cpu *data = per_cpu_ptr(buf->data, buf->cpu);
        struct tracer *type = iter->trace;
@@ -2664,20 +2666,22 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
 static void test_cpu_buff_start(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
+       struct trace_array *tr = iter->tr;
 
-       if (!(trace_flags & TRACE_ITER_ANNOTATE))
+       if (!(tr->trace_flags & TRACE_ITER_ANNOTATE))
                return;
 
        if (!(iter->iter_flags & TRACE_FILE_ANNOTATE))
                return;
 
-       if (cpumask_test_cpu(iter->cpu, iter->started))
+       if (iter->started && cpumask_test_cpu(iter->cpu, iter->started))
                return;
 
        if (per_cpu_ptr(iter->trace_buffer->data, iter->cpu)->skipped_entries)
                return;
 
-       cpumask_set_cpu(iter->cpu, iter->started);
+       if (iter->started)
+               cpumask_set_cpu(iter->cpu, iter->started);
 
        /* Don't print started cpu buffer for the first entry of the trace */
        if (iter->idx > 1)
@@ -2687,8 +2691,9 @@ static void test_cpu_buff_start(struct trace_iterator *iter)
 
 static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
-       unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
+       unsigned long sym_flags = (tr->trace_flags & TRACE_ITER_SYM_MASK);
        struct trace_entry *entry;
        struct trace_event *event;
 
@@ -2698,7 +2703,7 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
 
        event = ftrace_find_event(entry->type);
 
-       if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
+       if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO) {
                if (iter->iter_flags & TRACE_FILE_LAT_FMT)
                        trace_print_lat_context(iter);
                else
@@ -2718,13 +2723,14 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
 
 static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry;
        struct trace_event *event;
 
        entry = iter->ent;
 
-       if (trace_flags & TRACE_ITER_CONTEXT_INFO)
+       if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO)
                trace_seq_printf(s, "%d %d %llu ",
                                 entry->pid, iter->cpu, iter->ts);
 
@@ -2742,6 +2748,7 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
 
 static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        unsigned char newline = '\n';
        struct trace_entry *entry;
@@ -2749,7 +2756,7 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 
        entry = iter->ent;
 
-       if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
+       if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO) {
                SEQ_PUT_HEX_FIELD(s, entry->pid);
                SEQ_PUT_HEX_FIELD(s, iter->cpu);
                SEQ_PUT_HEX_FIELD(s, iter->ts);
@@ -2771,13 +2778,14 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 
 static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry;
        struct trace_event *event;
 
        entry = iter->ent;
 
-       if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
+       if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO) {
                SEQ_PUT_FIELD(s, entry->pid);
                SEQ_PUT_FIELD(s, iter->cpu);
                SEQ_PUT_FIELD(s, iter->ts);
@@ -2826,6 +2834,8 @@ int trace_empty(struct trace_iterator *iter)
 /*  Called with trace_event_read_lock() held. */
 enum print_line_t print_trace_line(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
+       unsigned long trace_flags = tr->trace_flags;
        enum print_line_t ret;
 
        if (iter->lost_events) {
@@ -2871,6 +2881,7 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
 void trace_latency_header(struct seq_file *m)
 {
        struct trace_iterator *iter = m->private;
+       struct trace_array *tr = iter->tr;
 
        /* print nothing if the buffers are empty */
        if (trace_empty(iter))
@@ -2879,13 +2890,15 @@ void trace_latency_header(struct seq_file *m)
        if (iter->iter_flags & TRACE_FILE_LAT_FMT)
                print_trace_header(m, iter);
 
-       if (!(trace_flags & TRACE_ITER_VERBOSE))
+       if (!(tr->trace_flags & TRACE_ITER_VERBOSE))
                print_lat_help_header(m);
 }
 
 void trace_default_header(struct seq_file *m)
 {
        struct trace_iterator *iter = m->private;
+       struct trace_array *tr = iter->tr;
+       unsigned long trace_flags = tr->trace_flags;
 
        if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
                return;
@@ -3230,7 +3243,7 @@ static int tracing_open(struct inode *inode, struct file *file)
                iter = __tracing_open(inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
-               else if (trace_flags & TRACE_ITER_LATENCY_FMT)
+               else if (tr->trace_flags & TRACE_ITER_LATENCY_FMT)
                        iter->iter_flags |= TRACE_FILE_LAT_FMT;
        }
 
@@ -3477,7 +3490,7 @@ static int tracing_trace_options_show(struct seq_file *m, void *v)
        trace_opts = tr->current_trace->flags->opts;
 
        for (i = 0; trace_options[i]; i++) {
-               if (trace_flags & (1 << i))
+               if (tr->trace_flags & (1 << i))
                        seq_printf(m, "%s\n", trace_options[i]);
                else
                        seq_printf(m, "no%s\n", trace_options[i]);
@@ -3542,7 +3555,7 @@ int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
 int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
 {
        /* do nothing if flag is already set */
-       if (!!(trace_flags & mask) == !!enabled)
+       if (!!(tr->trace_flags & mask) == !!enabled)
                return 0;
 
        /* Give the tracer a chance to approve the change */
@@ -3551,9 +3564,9 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
                        return -EINVAL;
 
        if (enabled)
-               trace_flags |= mask;
+               tr->trace_flags |= mask;
        else
-               trace_flags &= ~mask;
+               tr->trace_flags &= ~mask;
 
        if (mask == TRACE_ITER_RECORD_CMD)
                trace_event_enable_cmd_record(enabled);
@@ -3565,8 +3578,10 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
 #endif
        }
 
-       if (mask == TRACE_ITER_PRINTK)
+       if (mask == TRACE_ITER_PRINTK) {
                trace_printk_start_stop_comm(enabled);
+               trace_printk_control(enabled);
+       }
 
        return 0;
 }
@@ -3577,6 +3592,7 @@ static int trace_set_options(struct trace_array *tr, char *option)
        int neg = 0;
        int ret = -ENODEV;
        int i;
+       size_t orig_len = strlen(option);
 
        cmp = strstrip(option);
 
@@ -3600,9 +3616,36 @@ static int trace_set_options(struct trace_array *tr, char *option)
 
        mutex_unlock(&trace_types_lock);
 
+       /*
+        * If the first trailing whitespace is replaced with '\0' by strstrip,
+        * turn it back into a space.
+        */
+       if (orig_len > strlen(option))
+               option[strlen(option)] = ' ';
+
        return ret;
 }
 
+static void __init apply_trace_boot_options(void)
+{
+       char *buf = trace_boot_options_buf;
+       char *option;
+
+       while (true) {
+               option = strsep(&buf, ",");
+
+               if (!option)
+                       break;
+
+               if (*option)
+                       trace_set_options(&global_trace, option);
+
+               /* Put back the comma to allow this to be called again */
+               if (buf)
+                       *(buf - 1) = ',';
+       }
+}
+
 static ssize_t
 tracing_trace_options_write(struct file *filp, const char __user *ubuf,
                        size_t cnt, loff_t *ppos)
@@ -4297,11 +4340,8 @@ int tracing_update_buffers(void)
 
 struct trace_option_dentry;
 
-static struct trace_option_dentry *
-create_trace_option_files(struct trace_array *tr, struct tracer *tracer);
-
 static void
-destroy_trace_option_files(struct trace_option_dentry *topts);
+create_trace_option_files(struct trace_array *tr, struct tracer *tracer);
 
 /*
  * Used to clear out the tracer before deletion of an instance.
@@ -4320,20 +4360,13 @@ static void tracing_set_nop(struct trace_array *tr)
        tr->current_trace = &nop_trace;
 }
 
-static void update_tracer_options(struct trace_array *tr, struct tracer *t)
+static void add_tracer_options(struct trace_array *tr, struct tracer *t)
 {
-       static struct trace_option_dentry *topts;
-
        /* Only enable if the directory has been created already. */
        if (!tr->dir)
                return;
 
-       /* Currently, only the top instance has options */
-       if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL))
-               return;
-
-       destroy_trace_option_files(topts);
-       topts = create_trace_option_files(tr, t);
+       create_trace_option_files(tr, t);
 }
 
 static int tracing_set_tracer(struct trace_array *tr, const char *buf)
@@ -4402,7 +4435,6 @@ static int tracing_set_tracer(struct trace_array *tr, const char *buf)
                free_snapshot(tr);
        }
 #endif
-       update_tracer_options(tr, t);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
        if (t->use_max_tr && !had_max_tr) {
@@ -4569,7 +4601,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        /* trace pipe does not show start of buffer */
        cpumask_setall(iter->started);
 
-       if (trace_flags & TRACE_ITER_LATENCY_FMT)
+       if (tr->trace_flags & TRACE_ITER_LATENCY_FMT)
                iter->iter_flags |= TRACE_FILE_LAT_FMT;
 
        /* Output in nanoseconds only if we are using a clock in nanoseconds. */
@@ -4626,11 +4658,13 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
 static unsigned int
 trace_poll(struct trace_iterator *iter, struct file *filp, poll_table *poll_table)
 {
+       struct trace_array *tr = iter->tr;
+
        /* Iterators are static, they should be filled or empty */
        if (trace_buffer_iter(iter, iter->cpu_file))
                return POLLIN | POLLRDNORM;
 
-       if (trace_flags & TRACE_ITER_BLOCK)
+       if (tr->trace_flags & TRACE_ITER_BLOCK)
                /*
                 * Always select as readable when in blocking mode
                 */
@@ -5047,7 +5081,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
        struct trace_array *tr = inode->i_private;
 
        /* disable tracing ? */
-       if (trace_flags & TRACE_ITER_STOP_ON_FREE)
+       if (tr->trace_flags & TRACE_ITER_STOP_ON_FREE)
                tracer_tracing_off(tr);
        /* resize the ring buffer to 0 */
        tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
@@ -5080,7 +5114,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
        if (tracing_disabled)
                return -EINVAL;
 
-       if (!(trace_flags & TRACE_ITER_MARKERS))
+       if (!(tr->trace_flags & TRACE_ITER_MARKERS))
                return -EINVAL;
 
        if (cnt > TRACE_BUF_SIZE)
@@ -6132,13 +6166,6 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
 #include "trace_selftest.c"
 #endif
 
-struct trace_option_dentry {
-       struct tracer_opt               *opt;
-       struct tracer_flags             *flags;
-       struct trace_array              *tr;
-       struct dentry                   *entry;
-};
-
 static ssize_t
 trace_options_read(struct file *filp, char __user *ubuf, size_t cnt,
                        loff_t *ppos)
@@ -6191,14 +6218,51 @@ static const struct file_operations trace_options_fops = {
        .llseek = generic_file_llseek,
 };
 
+/*
+ * In order to pass in both the trace_array descriptor as well as the index
+ * to the flag that the trace option file represents, the trace_array
+ * has a character array of trace_flags_index[], which holds the index
+ * of the bit for the flag it represents. index[0] == 0, index[1] == 1, etc.
+ * The address of this character array is passed to the flag option file
+ * read/write callbacks.
+ *
+ * In order to extract both the index and the trace_array descriptor,
+ * get_tr_index() uses the following algorithm.
+ *
+ *   idx = *ptr;
+ *
+ * As the pointer itself contains the address of the index (remember
+ * index[1] == 1).
+ *
+ * Then to get the trace_array descriptor, by subtracting that index
+ * from the ptr, we get to the start of the index itself.
+ *
+ *   ptr - idx == &index[0]
+ *
+ * Then a simple container_of() from that pointer gets us to the
+ * trace_array descriptor.
+ */
+static void get_tr_index(void *data, struct trace_array **ptr,
+                        unsigned int *pindex)
+{
+       *pindex = *(unsigned char *)data;
+
+       *ptr = container_of(data - *pindex, struct trace_array,
+                           trace_flags_index);
+}
+
 static ssize_t
 trace_options_core_read(struct file *filp, char __user *ubuf, size_t cnt,
                        loff_t *ppos)
 {
-       long index = (long)filp->private_data;
+       void *tr_index = filp->private_data;
+       struct trace_array *tr;
+       unsigned int index;
        char *buf;
 
-       if (trace_flags & (1 << index))
+       get_tr_index(tr_index, &tr, &index);
+
+       if (tr->trace_flags & (1 << index))
                buf = "1\n";
        else
                buf = "0\n";
@@ -6210,11 +6274,14 @@ static ssize_t
 trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
                         loff_t *ppos)
 {
-       struct trace_array *tr = &global_trace;
-       long index = (long)filp->private_data;
+       void *tr_index = filp->private_data;
+       struct trace_array *tr;
+       unsigned int index;
        unsigned long val;
        int ret;
 
+       get_tr_index(tr_index, &tr, &index);
+
        ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
        if (ret)
                return ret;
@@ -6298,21 +6365,39 @@ create_trace_option_file(struct trace_array *tr,
 
 }
 
-static struct trace_option_dentry *
+static void
 create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
 {
        struct trace_option_dentry *topts;
+       struct trace_options *tr_topts;
        struct tracer_flags *flags;
        struct tracer_opt *opts;
        int cnt;
+       int i;
 
        if (!tracer)
-               return NULL;
+               return;
 
        flags = tracer->flags;
 
        if (!flags || !flags->opts)
-               return NULL;
+               return;
+
+       /*
+        * If this is an instance, only create flags for tracers
+        * the instance may have.
+        */
+       if (!trace_ok_for_array(tracer, tr))
+               return;
+
+       for (i = 0; i < tr->nr_topts; i++) {
+               /*
+                * Check if these flags have already been added.
+                * Some tracers share flags.
+                */
+               if (tr->topts[i].tracer->flags == tracer->flags)
+                       return;
+       }
 
        opts = flags->opts;
 
@@ -6321,27 +6406,27 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
 
        topts = kcalloc(cnt + 1, sizeof(*topts), GFP_KERNEL);
        if (!topts)
-               return NULL;
-
-       for (cnt = 0; opts[cnt].name; cnt++)
-               create_trace_option_file(tr, &topts[cnt], flags,
-                                        &opts[cnt]);
-
-       return topts;
-}
-
-static void
-destroy_trace_option_files(struct trace_option_dentry *topts)
-{
-       int cnt;
+               return;
 
-       if (!topts)
+       tr_topts = krealloc(tr->topts, sizeof(*tr->topts) * (tr->nr_topts + 1),
+                           GFP_KERNEL);
+       if (!tr_topts) {
+               kfree(topts);
                return;
+       }
 
-       for (cnt = 0; topts[cnt].opt; cnt++)
-               tracefs_remove(topts[cnt].entry);
+       tr->topts = tr_topts;
+       tr->topts[tr->nr_topts].tracer = tracer;
+       tr->topts[tr->nr_topts].topts = topts;
+       tr->nr_topts++;
 
-       kfree(topts);
+       for (cnt = 0; opts[cnt].name; cnt++) {
+               create_trace_option_file(tr, &topts[cnt], flags,
+                                        &opts[cnt]);
+               WARN_ONCE(topts[cnt].entry == NULL,
+                         "Failed to create trace option: %s",
+                         opts[cnt].name);
+       }
 }
 
 static struct dentry *
@@ -6354,21 +6439,26 @@ create_trace_option_core_file(struct trace_array *tr,
        if (!t_options)
                return NULL;
 
-       return trace_create_file(option, 0644, t_options, (void *)index,
-                                   &trace_options_core_fops);
+       return trace_create_file(option, 0644, t_options,
+                                (void *)&tr->trace_flags_index[index],
+                                &trace_options_core_fops);
 }
 
-static __init void create_trace_options_dir(struct trace_array *tr)
+static void create_trace_options_dir(struct trace_array *tr)
 {
        struct dentry *t_options;
+       bool top_level = tr == &global_trace;
        int i;
 
        t_options = trace_options_init_dentry(tr);
        if (!t_options)
                return;
 
-       for (i = 0; trace_options[i]; i++)
-               create_trace_option_core_file(tr, trace_options[i], i);
+       for (i = 0; trace_options[i]; i++) {
+               if (top_level ||
+                   !((1 << i) & TOP_LEVEL_TRACE_FLAGS))
+                       create_trace_option_core_file(tr, trace_options[i], i);
+       }
 }
 
 static ssize_t
@@ -6435,7 +6525,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
 {
        enum ring_buffer_flags rb_flags;
 
-       rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
+       rb_flags = tr->trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
 
        buf->tr = tr;
 
@@ -6505,6 +6595,30 @@ static void free_trace_buffers(struct trace_array *tr)
 #endif
 }
 
+static void init_trace_flags_index(struct trace_array *tr)
+{
+       int i;
+
+       /* Used by the trace options files */
+       for (i = 0; i < TRACE_FLAGS_MAX_SIZE; i++)
+               tr->trace_flags_index[i] = i;
+}
+
+static void __update_tracer_options(struct trace_array *tr)
+{
+       struct tracer *t;
+
+       for (t = trace_types; t; t = t->next)
+               add_tracer_options(tr, t);
+}
+
+static void update_tracer_options(struct trace_array *tr)
+{
+       mutex_lock(&trace_types_lock);
+       __update_tracer_options(tr);
+       mutex_unlock(&trace_types_lock);
+}
+
 static int instance_mkdir(const char *name)
 {
        struct trace_array *tr;
@@ -6530,6 +6644,8 @@ static int instance_mkdir(const char *name)
        if (!alloc_cpumask_var(&tr->tracing_cpumask, GFP_KERNEL))
                goto out_free_tr;
 
+       tr->trace_flags = global_trace.trace_flags;
+
        cpumask_copy(tr->tracing_cpumask, cpu_all_mask);
 
        raw_spin_lock_init(&tr->start_lock);
@@ -6555,6 +6671,8 @@ static int instance_mkdir(const char *name)
        }
 
        init_tracer_tracefs(tr, tr->dir);
+       init_trace_flags_index(tr);
+       __update_tracer_options(tr);
 
        list_add(&tr->list, &ftrace_trace_arrays);
 
@@ -6580,6 +6698,7 @@ static int instance_rmdir(const char *name)
        struct trace_array *tr;
        int found = 0;
        int ret;
+       int i;
 
        mutex_lock(&trace_types_lock);
 
@@ -6602,9 +6721,14 @@ static int instance_rmdir(const char *name)
        tracing_set_nop(tr);
        event_trace_del_tracer(tr);
        ftrace_destroy_function_files(tr);
-       debugfs_remove_recursive(tr->dir);
+       tracefs_remove_recursive(tr->dir);
        free_trace_buffers(tr);
 
+       for (i = 0; i < tr->nr_topts; i++) {
+               kfree(tr->topts[i].topts);
+       }
+       kfree(tr->topts);
+
        kfree(tr->name);
        kfree(tr);
 
@@ -6666,6 +6790,8 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
        trace_create_file("tracing_on", 0644, d_tracer,
                          tr, &rb_simple_fops);
 
+       create_trace_options_dir(tr);
+
 #ifdef CONFIG_TRACER_MAX_TRACE
        trace_create_file("tracing_max_latency", 0644, d_tracer,
                        &tr->max_latency, &tracing_max_lat_fops);
@@ -6861,11 +6987,7 @@ static __init int tracer_init_tracefs(void)
 
        create_trace_instances(d_tracer);
 
-       create_trace_options_dir(&global_trace);
-
-       /* If the tracer was started via cmdline, create options for it here */
-       if (global_trace.current_trace != &nop_trace)
-               update_tracer_options(&global_trace, global_trace.current_trace);
+       update_tracer_options(&global_trace);
 
        return 0;
 }
@@ -6964,6 +7086,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
        /* use static because iter can be a bit big for the stack */
        static struct trace_iterator iter;
        static atomic_t dump_running;
+       struct trace_array *tr = &global_trace;
        unsigned int old_userobj;
        unsigned long flags;
        int cnt = 0, cpu;
@@ -6993,10 +7116,10 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
                atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
        }
 
-       old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
+       old_userobj = tr->trace_flags & TRACE_ITER_SYM_USEROBJ;
 
        /* don't look at user memory in panic mode */
-       trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
+       tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
        switch (oops_dump_mode) {
        case DUMP_ALL:
@@ -7059,7 +7182,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
                printk(KERN_TRACE "---------------------------------\n");
 
  out_enable:
-       trace_flags |= old_userobj;
+       tr->trace_flags |= old_userobj;
 
        for_each_tracing_cpu(cpu) {
                atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
@@ -7074,6 +7197,12 @@ __init static int tracer_alloc_buffers(void)
        int ring_buf_size;
        int ret = -ENOMEM;
 
+       /*
+        * Make sure we don't accidently add more trace options
+        * than we have bits for.
+        */
+       BUILD_BUG_ON(TRACE_ITER_LAST_BIT > TRACE_FLAGS_MAX_SIZE);
+
        if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
                goto out;
 
@@ -7132,6 +7261,8 @@ __init static int tracer_alloc_buffers(void)
 
        ftrace_init_global_array_ops(&global_trace);
 
+       init_trace_flags_index(&global_trace);
+
        register_tracer(&nop_trace);
 
        /* All seems OK, enable tracing */
@@ -7148,12 +7279,7 @@ __init static int tracer_alloc_buffers(void)
        INIT_LIST_HEAD(&global_trace.events);
        list_add(&global_trace.list, &ftrace_trace_arrays);
 
-       while (trace_boot_options) {
-               char *option;
-
-               option = strsep(&trace_boot_options, ",");
-               trace_set_options(&global_trace, option);
-       }
+       apply_trace_boot_options();
 
        register_snapshot_cmd();
 
index 74bde81601a902759e5714b04a5a987ddbde2d15..dd7620802e725e1e2f262f77ba7d8c76dda98ef9 100644 (file)
@@ -71,9 +71,6 @@ enum trace_type {
                tstruct                                                 \
        }
 
-#undef TP_ARGS
-#define TP_ARGS(args...)       args
-
 #undef FTRACE_ENTRY_DUP
 #define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk, filter)
 
@@ -156,9 +153,12 @@ struct trace_array_cpu {
        pid_t                   pid;
        kuid_t                  uid;
        char                    comm[TASK_COMM_LEN];
+
+       bool                    ignore_pid;
 };
 
 struct tracer;
+struct trace_option_dentry;
 
 struct trace_buffer {
        struct trace_array              *tr;
@@ -168,6 +168,19 @@ struct trace_buffer {
        int                             cpu;
 };
 
+#define TRACE_FLAGS_MAX_SIZE           32
+
+struct trace_options {
+       struct tracer                   *tracer;
+       struct trace_option_dentry      *topts;
+};
+
+struct trace_pid_list {
+       unsigned int                    nr_pids;
+       int                             order;
+       pid_t                           *pids;
+};
+
 /*
  * The trace array - an array of per-CPU trace arrays. This is the
  * highest level data structure that individual tracers deal with.
@@ -193,6 +206,7 @@ struct trace_array {
        bool                    allocated_snapshot;
        unsigned long           max_latency;
 #endif
+       struct trace_pid_list   __rcu *filtered_pids;
        /*
         * max_lock is used to protect the swapping of buffers
         * when taking a max snapshot. The buffers themselves are
@@ -216,13 +230,17 @@ struct trace_array {
 #endif
        int                     stop_count;
        int                     clock_id;
+       int                     nr_topts;
        struct tracer           *current_trace;
+       unsigned int            trace_flags;
+       unsigned char           trace_flags_index[TRACE_FLAGS_MAX_SIZE];
        unsigned int            flags;
        raw_spinlock_t          start_lock;
        struct dentry           *dir;
        struct dentry           *options;
        struct dentry           *percpu_dir;
        struct dentry           *event_dir;
+       struct trace_options    *topts;
        struct list_head        systems;
        struct list_head        events;
        cpumask_var_t           tracing_cpumask; /* only trace on set CPUs */
@@ -333,6 +351,13 @@ struct tracer_flags {
 #define TRACER_OPT(s, b)       .name = #s, .bit = b
 
 
+struct trace_option_dentry {
+       struct tracer_opt               *opt;
+       struct tracer_flags             *flags;
+       struct trace_array              *tr;
+       struct dentry                   *entry;
+};
+
 /**
  * struct tracer - a specific tracer and its callbacks to interact with tracefs
  * @name: the name chosen to select it on the available_tracers file
@@ -611,29 +636,12 @@ void update_max_tr_single(struct trace_array *tr,
 #endif /* CONFIG_TRACER_MAX_TRACE */
 
 #ifdef CONFIG_STACKTRACE
-void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
-                       int skip, int pc);
-
-void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags,
-                            int skip, int pc, struct pt_regs *regs);
-
 void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags,
                            int pc);
 
 void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
                   int pc);
 #else
-static inline void ftrace_trace_stack(struct ring_buffer *buffer,
-                                     unsigned long flags, int skip, int pc)
-{
-}
-
-static inline void ftrace_trace_stack_regs(struct ring_buffer *buffer,
-                                          unsigned long flags, int skip,
-                                          int pc, struct pt_regs *regs)
-{
-}
-
 static inline void ftrace_trace_userstack(struct ring_buffer *buffer,
                                          unsigned long flags, int pc)
 {
@@ -707,8 +715,6 @@ int trace_array_printk_buf(struct ring_buffer *buffer,
 void trace_printk_seq(struct trace_seq *s);
 enum print_line_t print_trace_line(struct trace_iterator *iter);
 
-extern unsigned long trace_flags;
-
 extern char trace_find_mark(unsigned long long duration);
 
 /* Standard output formatting function used for function return traces */
@@ -723,9 +729,14 @@ extern char trace_find_mark(unsigned long long duration);
 #define TRACE_GRAPH_PRINT_ABS_TIME      0x20
 #define TRACE_GRAPH_PRINT_IRQS          0x40
 #define TRACE_GRAPH_PRINT_TAIL          0x80
+#define TRACE_GRAPH_SLEEP_TIME         0x100
+#define TRACE_GRAPH_GRAPH_TIME         0x200
 #define TRACE_GRAPH_PRINT_FILL_SHIFT   28
 #define TRACE_GRAPH_PRINT_FILL_MASK    (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
 
+extern void ftrace_graph_sleep_time_control(bool enable);
+extern void ftrace_graph_graph_time_control(bool enable);
+
 extern enum print_line_t
 print_graph_function_flags(struct trace_iterator *iter, u32 flags);
 extern void print_graph_headers_flags(struct seq_file *s, u32 flags);
@@ -859,7 +870,7 @@ void ftrace_destroy_filter_files(struct ftrace_ops *ops);
 #define ftrace_destroy_filter_files(ops) do { } while (0)
 #endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */
 
-int ftrace_event_is_function(struct trace_event_call *call);
+bool ftrace_event_is_function(struct trace_event_call *call);
 
 /*
  * struct trace_parser - servers for reading the user input separated by spaces
@@ -896,42 +907,94 @@ extern void trace_parser_put(struct trace_parser *parser);
 extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
        size_t cnt, loff_t *ppos);
 
+/*
+ * Only create function graph options if function graph is configured.
+ */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+# define FGRAPH_FLAGS                                          \
+               C(DISPLAY_GRAPH,        "display-graph"),
+#else
+# define FGRAPH_FLAGS
+#endif
+
+#ifdef CONFIG_BRANCH_TRACER
+# define BRANCH_FLAGS                                  \
+               C(BRANCH,               "branch"),
+#else
+# define BRANCH_FLAGS
+#endif
+
+#ifdef CONFIG_FUNCTION_TRACER
+# define FUNCTION_FLAGS                                                \
+               C(FUNCTION,             "function-trace"),
+# define FUNCTION_DEFAULT_FLAGS                TRACE_ITER_FUNCTION
+#else
+# define FUNCTION_FLAGS
+# define FUNCTION_DEFAULT_FLAGS                0UL
+#endif
+
+#ifdef CONFIG_STACKTRACE
+# define STACK_FLAGS                           \
+               C(STACKTRACE,           "stacktrace"),
+#else
+# define STACK_FLAGS
+#endif
+
 /*
  * trace_iterator_flags is an enumeration that defines bit
  * positions into trace_flags that controls the output.
  *
  * NOTE: These bits must match the trace_options array in
- *       trace.c.
+ *       trace.c (this macro guarantees it).
+ */
+#define TRACE_FLAGS                                            \
+               C(PRINT_PARENT,         "print-parent"),        \
+               C(SYM_OFFSET,           "sym-offset"),          \
+               C(SYM_ADDR,             "sym-addr"),            \
+               C(VERBOSE,              "verbose"),             \
+               C(RAW,                  "raw"),                 \
+               C(HEX,                  "hex"),                 \
+               C(BIN,                  "bin"),                 \
+               C(BLOCK,                "block"),               \
+               C(PRINTK,               "trace_printk"),        \
+               C(ANNOTATE,             "annotate"),            \
+               C(USERSTACKTRACE,       "userstacktrace"),      \
+               C(SYM_USEROBJ,          "sym-userobj"),         \
+               C(PRINTK_MSGONLY,       "printk-msg-only"),     \
+               C(CONTEXT_INFO,         "context-info"),   /* Print pid/cpu/time */ \
+               C(LATENCY_FMT,          "latency-format"),      \
+               C(RECORD_CMD,           "record-cmd"),          \
+               C(OVERWRITE,            "overwrite"),           \
+               C(STOP_ON_FREE,         "disable_on_free"),     \
+               C(IRQ_INFO,             "irq-info"),            \
+               C(MARKERS,              "markers"),             \
+               FUNCTION_FLAGS                                  \
+               FGRAPH_FLAGS                                    \
+               STACK_FLAGS                                     \
+               BRANCH_FLAGS
+
+/*
+ * By defining C, we can make TRACE_FLAGS a list of bit names
+ * that will define the bits for the flag masks.
  */
-enum trace_iterator_flags {
-       TRACE_ITER_PRINT_PARENT         = 0x01,
-       TRACE_ITER_SYM_OFFSET           = 0x02,
-       TRACE_ITER_SYM_ADDR             = 0x04,
-       TRACE_ITER_VERBOSE              = 0x08,
-       TRACE_ITER_RAW                  = 0x10,
-       TRACE_ITER_HEX                  = 0x20,
-       TRACE_ITER_BIN                  = 0x40,
-       TRACE_ITER_BLOCK                = 0x80,
-       TRACE_ITER_STACKTRACE           = 0x100,
-       TRACE_ITER_PRINTK               = 0x200,
-       TRACE_ITER_PREEMPTONLY          = 0x400,
-       TRACE_ITER_BRANCH               = 0x800,
-       TRACE_ITER_ANNOTATE             = 0x1000,
-       TRACE_ITER_USERSTACKTRACE       = 0x2000,
-       TRACE_ITER_SYM_USEROBJ          = 0x4000,
-       TRACE_ITER_PRINTK_MSGONLY       = 0x8000,
-       TRACE_ITER_CONTEXT_INFO         = 0x10000, /* Print pid/cpu/time */
-       TRACE_ITER_LATENCY_FMT          = 0x20000,
-       TRACE_ITER_SLEEP_TIME           = 0x40000,
-       TRACE_ITER_GRAPH_TIME           = 0x80000,
-       TRACE_ITER_RECORD_CMD           = 0x100000,
-       TRACE_ITER_OVERWRITE            = 0x200000,
-       TRACE_ITER_STOP_ON_FREE         = 0x400000,
-       TRACE_ITER_IRQ_INFO             = 0x800000,
-       TRACE_ITER_MARKERS              = 0x1000000,
-       TRACE_ITER_FUNCTION             = 0x2000000,
+#undef C
+#define C(a, b) TRACE_ITER_##a##_BIT
+
+enum trace_iterator_bits {
+       TRACE_FLAGS
+       /* Make sure we don't go more than we have bits for */
+       TRACE_ITER_LAST_BIT
 };
 
+/*
+ * By redefining C, we can make TRACE_FLAGS a list of masks that
+ * use the bits as defined above.
+ */
+#undef C
+#define C(a, b) TRACE_ITER_##a = (1 << TRACE_ITER_##a##_BIT)
+
+enum trace_iterator_flags { TRACE_FLAGS };
+
 /*
  * TRACE_ITER_SYM_MASK masks the options in trace_flags that
  * control the output of kernel symbols.
@@ -946,7 +1009,7 @@ extern int enable_branch_tracing(struct trace_array *tr);
 extern void disable_branch_tracing(void);
 static inline int trace_branch_enable(struct trace_array *tr)
 {
-       if (trace_flags & TRACE_ITER_BRANCH)
+       if (tr->trace_flags & TRACE_ITER_BRANCH)
                return enable_branch_tracing(tr);
        return 0;
 }
@@ -1269,6 +1332,7 @@ extern const char *__stop___trace_bprintk_fmt[];
 extern const char *__start___tracepoint_str[];
 extern const char *__stop___tracepoint_str[];
 
+void trace_printk_control(bool enabled);
 void trace_printk_init_buffers(void);
 void trace_printk_start_comm(void);
 int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
index 40a14cbcf8e01b5d2c32663fa3666c91be582f67..0f109c4130d300384cc5e1a22d4fbbb98ed1539f 100644 (file)
@@ -43,7 +43,7 @@ static void trace_do_benchmark(void)
        unsigned int std = 0;
 
        /* Only run if the tracepoint is actually active */
-       if (!trace_benchmark_event_enabled())
+       if (!trace_benchmark_event_enabled() || !tracing_is_on())
                return;
 
        local_irq_disable();
index e2e12ad3186f440f7841819a9f260509d5afde43..3a2a73716a5bd9ef56bec370f1eef4df3a7e0a0d 100644 (file)
@@ -125,25 +125,14 @@ void disable_branch_tracing(void)
        mutex_unlock(&branch_tracing_mutex);
 }
 
-static void start_branch_trace(struct trace_array *tr)
-{
-       enable_branch_tracing(tr);
-}
-
-static void stop_branch_trace(struct trace_array *tr)
-{
-       disable_branch_tracing();
-}
-
 static int branch_trace_init(struct trace_array *tr)
 {
-       start_branch_trace(tr);
-       return 0;
+       return enable_branch_tracing(tr);
 }
 
 static void branch_trace_reset(struct trace_array *tr)
 {
-       stop_branch_trace(tr);
+       disable_branch_tracing();
 }
 
 static enum print_line_t trace_branch_print(struct trace_iterator *iter,
index 7ca09cdc20c2f920faa004e32eb248e3bc92bf61..6bbc5f652355745d24f6252a93d7b437a0efea15 100644 (file)
 #include <linux/kthread.h>
 #include <linux/tracefs.h>
 #include <linux/uaccess.h>
+#include <linux/bsearch.h>
 #include <linux/module.h>
 #include <linux/ctype.h>
+#include <linux/sort.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 
+#include <trace/events/sched.h>
+
 #include <asm/setup.h>
 
 #include "trace_output.h"
@@ -38,21 +42,19 @@ static LIST_HEAD(ftrace_common_fields);
 static struct kmem_cache *field_cachep;
 static struct kmem_cache *file_cachep;
 
-#define SYSTEM_FL_FREE_NAME            (1 << 31)
-
 static inline int system_refcount(struct event_subsystem *system)
 {
-       return system->ref_count & ~SYSTEM_FL_FREE_NAME;
+       return system->ref_count;
 }
 
 static int system_refcount_inc(struct event_subsystem *system)
 {
-       return (system->ref_count++) & ~SYSTEM_FL_FREE_NAME;
+       return system->ref_count++;
 }
 
 static int system_refcount_dec(struct event_subsystem *system)
 {
-       return (--system->ref_count) & ~SYSTEM_FL_FREE_NAME;
+       return --system->ref_count;
 }
 
 /* Double loops, do not use break, only goto's work */
@@ -212,12 +214,32 @@ int trace_event_raw_init(struct trace_event_call *call)
 }
 EXPORT_SYMBOL_GPL(trace_event_raw_init);
 
+bool trace_event_ignore_this_pid(struct trace_event_file *trace_file)
+{
+       struct trace_array *tr = trace_file->tr;
+       struct trace_array_cpu *data;
+       struct trace_pid_list *pid_list;
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+       if (!pid_list)
+               return false;
+
+       data = this_cpu_ptr(tr->trace_buffer.data);
+
+       return data->ignore_pid;
+}
+EXPORT_SYMBOL_GPL(trace_event_ignore_this_pid);
+
 void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
                                 struct trace_event_file *trace_file,
                                 unsigned long len)
 {
        struct trace_event_call *event_call = trace_file->event_call;
 
+       if ((trace_file->flags & EVENT_FILE_FL_PID_FILTER) &&
+           trace_event_ignore_this_pid(trace_file))
+               return NULL;
+
        local_save_flags(fbuffer->flags);
        fbuffer->pc = preempt_count();
        fbuffer->trace_file = trace_file;
@@ -338,6 +360,7 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file,
                                         int enable, int soft_disable)
 {
        struct trace_event_call *call = file->event_call;
+       struct trace_array *tr = file->tr;
        int ret = 0;
        int disable;
 
@@ -401,7 +424,7 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file,
                        if (soft_disable)
                                set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags);
 
-                       if (trace_flags & TRACE_ITER_RECORD_CMD) {
+                       if (tr->trace_flags & TRACE_ITER_RECORD_CMD) {
                                tracing_start_cmdline_record();
                                set_bit(EVENT_FILE_FL_RECORDED_CMD_BIT, &file->flags);
                        }
@@ -446,6 +469,142 @@ static void ftrace_clear_events(struct trace_array *tr)
        mutex_unlock(&event_mutex);
 }
 
+static int cmp_pid(const void *key, const void *elt)
+{
+       const pid_t *search_pid = key;
+       const pid_t *pid = elt;
+
+       if (*search_pid == *pid)
+               return 0;
+       if (*search_pid < *pid)
+               return -1;
+       return 1;
+}
+
+static bool
+check_ignore_pid(struct trace_pid_list *filtered_pids, struct task_struct *task)
+{
+       pid_t search_pid;
+       pid_t *pid;
+
+       /*
+        * Return false, because if filtered_pids does not exist,
+        * all pids are good to trace.
+        */
+       if (!filtered_pids)
+               return false;
+
+       search_pid = task->pid;
+
+       pid = bsearch(&search_pid, filtered_pids->pids,
+                     filtered_pids->nr_pids, sizeof(pid_t),
+                     cmp_pid);
+       if (!pid)
+               return true;
+
+       return false;
+}
+
+static void
+event_filter_pid_sched_switch_probe_pre(void *data, bool preempt,
+                   struct task_struct *prev, struct task_struct *next)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       this_cpu_write(tr->trace_buffer.data->ignore_pid,
+                      check_ignore_pid(pid_list, prev) &&
+                      check_ignore_pid(pid_list, next));
+}
+
+static void
+event_filter_pid_sched_switch_probe_post(void *data, bool preempt,
+                   struct task_struct *prev, struct task_struct *next)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       this_cpu_write(tr->trace_buffer.data->ignore_pid,
+                      check_ignore_pid(pid_list, next));
+}
+
+static void
+event_filter_pid_sched_wakeup_probe_pre(void *data, struct task_struct *task)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       /* Nothing to do if we are already tracing */
+       if (!this_cpu_read(tr->trace_buffer.data->ignore_pid))
+               return;
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       this_cpu_write(tr->trace_buffer.data->ignore_pid,
+                      check_ignore_pid(pid_list, task));
+}
+
+static void
+event_filter_pid_sched_wakeup_probe_post(void *data, struct task_struct *task)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       /* Nothing to do if we are not tracing */
+       if (this_cpu_read(tr->trace_buffer.data->ignore_pid))
+               return;
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       /* Set tracing if current is enabled */
+       this_cpu_write(tr->trace_buffer.data->ignore_pid,
+                      check_ignore_pid(pid_list, current));
+}
+
+static void __ftrace_clear_event_pids(struct trace_array *tr)
+{
+       struct trace_pid_list *pid_list;
+       struct trace_event_file *file;
+       int cpu;
+
+       pid_list = rcu_dereference_protected(tr->filtered_pids,
+                                            lockdep_is_held(&event_mutex));
+       if (!pid_list)
+               return;
+
+       unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_pre, tr);
+       unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_post, tr);
+
+       unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr);
+       unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr);
+
+       list_for_each_entry(file, &tr->events, list) {
+               clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
+       }
+
+       for_each_possible_cpu(cpu)
+               per_cpu_ptr(tr->trace_buffer.data, cpu)->ignore_pid = false;
+
+       rcu_assign_pointer(tr->filtered_pids, NULL);
+
+       /* Wait till all users are no longer using pid filtering */
+       synchronize_sched();
+
+       free_pages((unsigned long)pid_list->pids, pid_list->order);
+       kfree(pid_list);
+}
+
+static void ftrace_clear_event_pids(struct trace_array *tr)
+{
+       mutex_lock(&event_mutex);
+       __ftrace_clear_event_pids(tr);
+       mutex_unlock(&event_mutex);
+}
+
 static void __put_system(struct event_subsystem *system)
 {
        struct event_filter *filter = system->filter;
@@ -460,8 +619,7 @@ static void __put_system(struct event_subsystem *system)
                kfree(filter->filter_string);
                kfree(filter);
        }
-       if (system->ref_count & SYSTEM_FL_FREE_NAME)
-               kfree(system->name);
+       kfree_const(system->name);
        kfree(system);
 }
 
@@ -779,6 +937,58 @@ static void t_stop(struct seq_file *m, void *p)
        mutex_unlock(&event_mutex);
 }
 
+static void *p_start(struct seq_file *m, loff_t *pos)
+       __acquires(RCU)
+{
+       struct trace_pid_list *pid_list;
+       struct trace_array *tr = m->private;
+
+       /*
+        * Grab the mutex, to keep calls to p_next() having the same
+        * tr->filtered_pids as p_start() has.
+        * If we just passed the tr->filtered_pids around, then RCU would
+        * have been enough, but doing that makes things more complex.
+        */
+       mutex_lock(&event_mutex);
+       rcu_read_lock_sched();
+
+       pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       if (!pid_list || *pos >= pid_list->nr_pids)
+               return NULL;
+
+       return (void *)&pid_list->pids[*pos];
+}
+
+static void p_stop(struct seq_file *m, void *p)
+       __releases(RCU)
+{
+       rcu_read_unlock_sched();
+       mutex_unlock(&event_mutex);
+}
+
+static void *
+p_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct trace_array *tr = m->private;
+       struct trace_pid_list *pid_list = rcu_dereference_sched(tr->filtered_pids);
+
+       (*pos)++;
+
+       if (*pos >= pid_list->nr_pids)
+               return NULL;
+
+       return (void *)&pid_list->pids[*pos];
+}
+
+static int p_show(struct seq_file *m, void *v)
+{
+       pid_t *pid = v;
+
+       seq_printf(m, "%d\n", *pid);
+       return 0;
+}
+
 static ssize_t
 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
@@ -1336,8 +1546,209 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
        return r;
 }
 
+static int max_pids(struct trace_pid_list *pid_list)
+{
+       return (PAGE_SIZE << pid_list->order) / sizeof(pid_t);
+}
+
+static void ignore_task_cpu(void *data)
+{
+       struct trace_array *tr = data;
+       struct trace_pid_list *pid_list;
+
+       /*
+        * This function is called by on_each_cpu() while the
+        * event_mutex is held.
+        */
+       pid_list = rcu_dereference_protected(tr->filtered_pids,
+                                            mutex_is_locked(&event_mutex));
+
+       this_cpu_write(tr->trace_buffer.data->ignore_pid,
+                      check_ignore_pid(pid_list, current));
+}
+
+static ssize_t
+ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
+                      size_t cnt, loff_t *ppos)
+{
+       struct seq_file *m = filp->private_data;
+       struct trace_array *tr = m->private;
+       struct trace_pid_list *filtered_pids = NULL;
+       struct trace_pid_list *pid_list = NULL;
+       struct trace_event_file *file;
+       struct trace_parser parser;
+       unsigned long val;
+       loff_t this_pos;
+       ssize_t read = 0;
+       ssize_t ret = 0;
+       pid_t pid;
+       int i;
+
+       if (!cnt)
+               return 0;
+
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
+       if (trace_parser_get_init(&parser, EVENT_BUF_SIZE + 1))
+               return -ENOMEM;
+
+       mutex_lock(&event_mutex);
+       /*
+        * Load as many pids into the array before doing a
+        * swap from the tr->filtered_pids to the new list.
+        */
+       while (cnt > 0) {
+
+               this_pos = 0;
+
+               ret = trace_get_user(&parser, ubuf, cnt, &this_pos);
+               if (ret < 0 || !trace_parser_loaded(&parser))
+                       break;
+
+               read += ret;
+               ubuf += ret;
+               cnt -= ret;
+
+               parser.buffer[parser.idx] = 0;
+
+               ret = -EINVAL;
+               if (kstrtoul(parser.buffer, 0, &val))
+                       break;
+               if (val > INT_MAX)
+                       break;
+
+               pid = (pid_t)val;
+
+               ret = -ENOMEM;
+               if (!pid_list) {
+                       pid_list = kmalloc(sizeof(*pid_list), GFP_KERNEL);
+                       if (!pid_list)
+                               break;
+
+                       filtered_pids = rcu_dereference_protected(tr->filtered_pids,
+                                                       lockdep_is_held(&event_mutex));
+                       if (filtered_pids)
+                               pid_list->order = filtered_pids->order;
+                       else
+                               pid_list->order = 0;
+
+                       pid_list->pids = (void *)__get_free_pages(GFP_KERNEL,
+                                                                 pid_list->order);
+                       if (!pid_list->pids)
+                               break;
+
+                       if (filtered_pids) {
+                               pid_list->nr_pids = filtered_pids->nr_pids;
+                               memcpy(pid_list->pids, filtered_pids->pids,
+                                      pid_list->nr_pids * sizeof(pid_t));
+                       } else
+                               pid_list->nr_pids = 0;
+               }
+
+               if (pid_list->nr_pids >= max_pids(pid_list)) {
+                       pid_t *pid_page;
+
+                       pid_page = (void *)__get_free_pages(GFP_KERNEL,
+                                                           pid_list->order + 1);
+                       if (!pid_page)
+                               break;
+                       memcpy(pid_page, pid_list->pids,
+                              pid_list->nr_pids * sizeof(pid_t));
+                       free_pages((unsigned long)pid_list->pids, pid_list->order);
+
+                       pid_list->order++;
+                       pid_list->pids = pid_page;
+               }
+
+               pid_list->pids[pid_list->nr_pids++] = pid;
+               trace_parser_clear(&parser);
+               ret = 0;
+       }
+       trace_parser_put(&parser);
+
+       if (ret < 0) {
+               if (pid_list)
+                       free_pages((unsigned long)pid_list->pids, pid_list->order);
+               kfree(pid_list);
+               mutex_unlock(&event_mutex);
+               return ret;
+       }
+
+       if (!pid_list) {
+               mutex_unlock(&event_mutex);
+               return ret;
+       }
+
+       sort(pid_list->pids, pid_list->nr_pids, sizeof(pid_t), cmp_pid, NULL);
+
+       /* Remove duplicates */
+       for (i = 1; i < pid_list->nr_pids; i++) {
+               int start = i;
+
+               while (i < pid_list->nr_pids &&
+                      pid_list->pids[i - 1] == pid_list->pids[i])
+                       i++;
+
+               if (start != i) {
+                       if (i < pid_list->nr_pids) {
+                               memmove(&pid_list->pids[start], &pid_list->pids[i],
+                                       (pid_list->nr_pids - i) * sizeof(pid_t));
+                               pid_list->nr_pids -= i - start;
+                               i = start;
+                       } else
+                               pid_list->nr_pids = start;
+               }
+       }
+
+       rcu_assign_pointer(tr->filtered_pids, pid_list);
+
+       list_for_each_entry(file, &tr->events, list) {
+               set_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
+       }
+
+       if (filtered_pids) {
+               synchronize_sched();
+
+               free_pages((unsigned long)filtered_pids->pids, filtered_pids->order);
+               kfree(filtered_pids);
+       } else {
+               /*
+                * Register a probe that is called before all other probes
+                * to set ignore_pid if next or prev do not match.
+                * Register a probe this is called after all other probes
+                * to only keep ignore_pid set if next pid matches.
+                */
+               register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_pre,
+                                                tr, INT_MAX);
+               register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_post,
+                                                tr, 0);
+
+               register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre,
+                                                tr, INT_MAX);
+               register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post,
+                                                tr, 0);
+       }
+
+       /*
+        * Ignoring of pids is done at task switch. But we have to
+        * check for those tasks that are currently running.
+        * Always do this in case a pid was appended or removed.
+        */
+       on_each_cpu(ignore_task_cpu, tr, 1);
+
+       mutex_unlock(&event_mutex);
+
+       ret = read;
+       *ppos += read;
+
+       return ret;
+}
+
 static int ftrace_event_avail_open(struct inode *inode, struct file *file);
 static int ftrace_event_set_open(struct inode *inode, struct file *file);
+static int ftrace_event_set_pid_open(struct inode *inode, struct file *file);
 static int ftrace_event_release(struct inode *inode, struct file *file);
 
 static const struct seq_operations show_event_seq_ops = {
@@ -1354,6 +1765,13 @@ static const struct seq_operations show_set_event_seq_ops = {
        .stop = t_stop,
 };
 
+static const struct seq_operations show_set_pid_seq_ops = {
+       .start = p_start,
+       .next = p_next,
+       .show = p_show,
+       .stop = p_stop,
+};
+
 static const struct file_operations ftrace_avail_fops = {
        .open = ftrace_event_avail_open,
        .read = seq_read,
@@ -1369,6 +1787,14 @@ static const struct file_operations ftrace_set_event_fops = {
        .release = ftrace_event_release,
 };
 
+static const struct file_operations ftrace_set_event_pid_fops = {
+       .open = ftrace_event_set_pid_open,
+       .read = seq_read,
+       .write = ftrace_event_pid_write,
+       .llseek = seq_lseek,
+       .release = ftrace_event_release,
+};
+
 static const struct file_operations ftrace_enable_fops = {
        .open = tracing_open_generic,
        .read = event_enable_read,
@@ -1479,6 +1905,26 @@ ftrace_event_set_open(struct inode *inode, struct file *file)
        return ret;
 }
 
+static int
+ftrace_event_set_pid_open(struct inode *inode, struct file *file)
+{
+       const struct seq_operations *seq_ops = &show_set_pid_seq_ops;
+       struct trace_array *tr = inode->i_private;
+       int ret;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
+       if ((file->f_mode & FMODE_WRITE) &&
+           (file->f_flags & O_TRUNC))
+               ftrace_clear_event_pids(tr);
+
+       ret = ftrace_event_open(inode, file, seq_ops);
+       if (ret < 0)
+               trace_array_put(tr);
+       return ret;
+}
+
 static struct event_subsystem *
 create_new_subsystem(const char *name)
 {
@@ -1492,13 +1938,9 @@ create_new_subsystem(const char *name)
        system->ref_count = 1;
 
        /* Only allocate if dynamic (kprobes and modules) */
-       if (!core_kernel_data((unsigned long)name)) {
-               system->ref_count |= SYSTEM_FL_FREE_NAME;
-               system->name = kstrdup(name, GFP_KERNEL);
-               if (!system->name)
-                       goto out_free;
-       } else
-               system->name = name;
+       system->name = kstrdup_const(name, GFP_KERNEL);
+       if (!system->name)
+               goto out_free;
 
        system->filter = NULL;
 
@@ -1511,8 +1953,7 @@ create_new_subsystem(const char *name)
        return system;
 
  out_free:
-       if (system->ref_count & SYSTEM_FL_FREE_NAME)
-               kfree(system->name);
+       kfree_const(system->name);
        kfree(system);
        return NULL;
 }
@@ -2478,6 +2919,9 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
                return -ENOMEM;
        }
 
+       entry = tracefs_create_file("set_event_pid", 0644, parent,
+                                   tr, &ftrace_set_event_pid_fops);
+
        /* ring buffer internal formats */
        trace_create_file("header_page", 0444, d_events,
                          ring_buffer_print_page_header,
@@ -2558,6 +3002,9 @@ int event_trace_del_tracer(struct trace_array *tr)
        /* Disable any event triggers and associated soft-disabled events */
        clear_event_triggers(tr);
 
+       /* Clear the pid list */
+       __ftrace_clear_event_pids(tr);
+
        /* Disable any running events */
        __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0);
 
@@ -2595,16 +3042,16 @@ early_enable_events(struct trace_array *tr, bool disable_first)
 
                if (!token)
                        break;
-               if (!*token)
-                       continue;
 
-               /* Restarting syscalls requires that we stop them first */
-               if (disable_first)
-                       ftrace_set_clr_event(tr, token, 0);
+               if (*token) {
+                       /* Restarting syscalls requires that we stop them first */
+                       if (disable_first)
+                               ftrace_set_clr_event(tr, token, 0);
 
-               ret = ftrace_set_clr_event(tr, token, 1);
-               if (ret)
-                       pr_warn("Failed to enable trace event: %s\n", token);
+                       ret = ftrace_set_clr_event(tr, token, 1);
+                       if (ret)
+                               pr_warn("Failed to enable trace event: %s\n", token);
+               }
 
                /* Put back the comma to allow this to be called again */
                if (buf)
@@ -2891,7 +3338,9 @@ static __init void event_trace_self_tests(void)
 
 static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable);
 
-static void
+static struct trace_array *event_tr;
+
+static void __init
 function_test_events_call(unsigned long ip, unsigned long parent_ip,
                          struct ftrace_ops *op, struct pt_regs *pt_regs)
 {
@@ -2922,7 +3371,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip,
        entry->ip                       = ip;
        entry->parent_ip                = parent_ip;
 
-       trace_buffer_unlock_commit(buffer, event, flags, pc);
+       trace_buffer_unlock_commit(event_tr, buffer, event, flags, pc);
 
  out:
        atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
@@ -2938,6 +3387,9 @@ static struct ftrace_ops trace_ops __initdata  =
 static __init void event_trace_self_test_with_function(void)
 {
        int ret;
+       event_tr = top_trace_array();
+       if (WARN_ON(!event_tr))
+               return;
        ret = register_ftrace_function(&trace_ops);
        if (WARN_ON(ret < 0)) {
                pr_info("Failed to enable function tracer for event tests\n");
index bd1bf184c5c98b6cc36d5c7e183bd4698702a514..f93a219b18daaa92ed314ad7ac4ba8e0ed3c4c09 100644 (file)
@@ -973,15 +973,15 @@ static bool is_string_field(struct ftrace_event_field *field)
               field->filter_type == FILTER_PTR_STRING;
 }
 
-static int is_legal_op(struct ftrace_event_field *field, int op)
+static bool is_legal_op(struct ftrace_event_field *field, int op)
 {
        if (is_string_field(field) &&
            (op != OP_EQ && op != OP_NE && op != OP_GLOB))
-               return 0;
+               return false;
        if (!is_string_field(field) && op == OP_GLOB)
-               return 0;
+               return false;
 
-       return 1;
+       return true;
 }
 
 static filter_pred_fn_t select_comparison_fn(int op, int field_size,
index adabf7da911389440297aaa41e455082946959e7..39aa7aa664686220ca55deca9952faf8528fca22 100644 (file)
@@ -187,7 +187,7 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
        FTRACE_ENTRY_REG(call, struct_name, etype,                      \
                         PARAMS(tstruct), PARAMS(print), filter, NULL)
 
-int ftrace_event_is_function(struct trace_event_call *call)
+bool ftrace_event_is_function(struct trace_event_call *call)
 {
        return call == &event_function;
 }
index ca98445782acaa83915a5ffb653a189bed1705b1..92382af7a21312c03ecef0cabdfbce19e2c8111e 100644 (file)
@@ -83,13 +83,18 @@ static struct tracer_opt trace_opts[] = {
        { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
        /* Display function name after trailing } */
        { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) },
+       /* Include sleep time (scheduled out) between entry and return */
+       { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) },
+       /* Include time within nested functions */
+       { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) },
        { } /* Empty entry */
 };
 
 static struct tracer_flags tracer_flags = {
        /* Don't display overruns, proc, or tail by default */
        .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD |
-              TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS,
+              TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS |
+              TRACE_GRAPH_SLEEP_TIME | TRACE_GRAPH_GRAPH_TIME,
        .opts = trace_opts
 };
 
@@ -107,8 +112,8 @@ enum {
 };
 
 static void
-print_graph_duration(unsigned long long duration, struct trace_seq *s,
-                    u32 flags);
+print_graph_duration(struct trace_array *tr, unsigned long long duration,
+                    struct trace_seq *s, u32 flags);
 
 /* Add a function return address to the trace stack on thread info.*/
 int
@@ -653,6 +658,7 @@ static void
 print_graph_irq(struct trace_iterator *iter, unsigned long addr,
                enum trace_type type, int cpu, pid_t pid, u32 flags)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
 
@@ -660,7 +666,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
                addr >= (unsigned long)__irqentry_text_end)
                return;
 
-       if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
+       if (tr->trace_flags & TRACE_ITER_CONTEXT_INFO) {
                /* Absolute time */
                if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
                        print_graph_abs_time(iter->ts, s);
@@ -676,19 +682,19 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
                }
 
                /* Latency format */
-               if (trace_flags & TRACE_ITER_LATENCY_FMT)
+               if (tr->trace_flags & TRACE_ITER_LATENCY_FMT)
                        print_graph_lat_fmt(s, ent);
        }
 
        /* No overhead */
-       print_graph_duration(0, s, flags | FLAGS_FILL_START);
+       print_graph_duration(tr, 0, s, flags | FLAGS_FILL_START);
 
        if (type == TRACE_GRAPH_ENT)
                trace_seq_puts(s, "==========>");
        else
                trace_seq_puts(s, "<==========");
 
-       print_graph_duration(0, s, flags | FLAGS_FILL_END);
+       print_graph_duration(tr, 0, s, flags | FLAGS_FILL_END);
        trace_seq_putc(s, '\n');
 }
 
@@ -726,11 +732,11 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
 }
 
 static void
-print_graph_duration(unsigned long long duration, struct trace_seq *s,
-                    u32 flags)
+print_graph_duration(struct trace_array *tr, unsigned long long duration,
+                    struct trace_seq *s, u32 flags)
 {
        if (!(flags & TRACE_GRAPH_PRINT_DURATION) ||
-           !(trace_flags & TRACE_ITER_CONTEXT_INFO))
+           !(tr->trace_flags & TRACE_ITER_CONTEXT_INFO))
                return;
 
        /* No real adata, just filling the column with spaces */
@@ -764,6 +770,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
                struct trace_seq *s, u32 flags)
 {
        struct fgraph_data *data = iter->private;
+       struct trace_array *tr = iter->tr;
        struct ftrace_graph_ret *graph_ret;
        struct ftrace_graph_ent *call;
        unsigned long long duration;
@@ -792,7 +799,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
        }
 
        /* Overhead and duration */
-       print_graph_duration(duration, s, flags);
+       print_graph_duration(tr, duration, s, flags);
 
        /* Function */
        for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
@@ -810,6 +817,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
 {
        struct ftrace_graph_ent *call = &entry->graph_ent;
        struct fgraph_data *data = iter->private;
+       struct trace_array *tr = iter->tr;
        int i;
 
        if (data) {
@@ -825,7 +833,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
        }
 
        /* No time */
-       print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
+       print_graph_duration(tr, 0, s, flags | FLAGS_FILL_FULL);
 
        /* Function */
        for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
@@ -849,6 +857,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
 {
        struct fgraph_data *data = iter->private;
        struct trace_entry *ent = iter->ent;
+       struct trace_array *tr = iter->tr;
        int cpu = iter->cpu;
 
        /* Pid */
@@ -858,7 +867,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
                /* Interrupt */
                print_graph_irq(iter, addr, type, cpu, ent->pid, flags);
 
-       if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
+       if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO))
                return;
 
        /* Absolute time */
@@ -876,7 +885,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
        }
 
        /* Latency format */
-       if (trace_flags & TRACE_ITER_LATENCY_FMT)
+       if (tr->trace_flags & TRACE_ITER_LATENCY_FMT)
                print_graph_lat_fmt(s, ent);
 
        return;
@@ -1027,6 +1036,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
 {
        unsigned long long duration = trace->rettime - trace->calltime;
        struct fgraph_data *data = iter->private;
+       struct trace_array *tr = iter->tr;
        pid_t pid = ent->pid;
        int cpu = iter->cpu;
        int func_match = 1;
@@ -1058,7 +1068,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
        print_graph_prologue(iter, s, 0, 0, flags);
 
        /* Overhead and duration */
-       print_graph_duration(duration, s, flags);
+       print_graph_duration(tr, duration, s, flags);
 
        /* Closing brace */
        for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++)
@@ -1091,7 +1101,8 @@ static enum print_line_t
 print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
                    struct trace_iterator *iter, u32 flags)
 {
-       unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
+       struct trace_array *tr = iter->tr;
+       unsigned long sym_flags = (tr->trace_flags & TRACE_ITER_SYM_MASK);
        struct fgraph_data *data = iter->private;
        struct trace_event *event;
        int depth = 0;
@@ -1104,7 +1115,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
        print_graph_prologue(iter, s, 0, 0, flags);
 
        /* No time */
-       print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
+       print_graph_duration(tr, 0, s, flags | FLAGS_FILL_FULL);
 
        /* Indentation */
        if (depth > 0)
@@ -1245,9 +1256,10 @@ static void print_lat_header(struct seq_file *s, u32 flags)
        seq_printf(s, "#%.*s||| /                      \n", size, spaces);
 }
 
-static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
+static void __print_graph_headers_flags(struct trace_array *tr,
+                                       struct seq_file *s, u32 flags)
 {
-       int lat = trace_flags & TRACE_ITER_LATENCY_FMT;
+       int lat = tr->trace_flags & TRACE_ITER_LATENCY_FMT;
 
        if (lat)
                print_lat_header(s, flags);
@@ -1289,11 +1301,12 @@ static void print_graph_headers(struct seq_file *s)
 void print_graph_headers_flags(struct seq_file *s, u32 flags)
 {
        struct trace_iterator *iter = s->private;
+       struct trace_array *tr = iter->tr;
 
-       if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
+       if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO))
                return;
 
-       if (trace_flags & TRACE_ITER_LATENCY_FMT) {
+       if (tr->trace_flags & TRACE_ITER_LATENCY_FMT) {
                /* print nothing if the buffers are empty */
                if (trace_empty(iter))
                        return;
@@ -1301,7 +1314,7 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags)
                print_trace_header(s, iter);
        }
 
-       __print_graph_headers_flags(s, flags);
+       __print_graph_headers_flags(tr, s, flags);
 }
 
 void graph_trace_open(struct trace_iterator *iter)
@@ -1362,6 +1375,12 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
        if (bit == TRACE_GRAPH_PRINT_IRQS)
                ftrace_graph_skip_irqs = !set;
 
+       if (bit == TRACE_GRAPH_SLEEP_TIME)
+               ftrace_graph_sleep_time_control(set);
+
+       if (bit == TRACE_GRAPH_GRAPH_TIME)
+               ftrace_graph_graph_time_control(set);
+
        return 0;
 }
 
index 8523ea345f2b1a3849d53f2d6731ed41fb5d94f4..e4e56589ec1d392c1734ddff45e87b6fc2dde2fb 100644 (file)
@@ -31,7 +31,6 @@ enum {
 static int trace_type __read_mostly;
 
 static int save_flags;
-static bool function_enabled;
 
 static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
 static int start_irqsoff_tracer(struct trace_array *tr, int graph);
@@ -57,22 +56,16 @@ irq_trace(void)
 # define irq_trace() (0)
 #endif
 
-#define TRACE_DISPLAY_GRAPH    1
-
-static struct tracer_opt trace_opts[] = {
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       /* display latency trace as call graph */
-       { TRACER_OPT(display-graph, TRACE_DISPLAY_GRAPH) },
+static int irqsoff_display_graph(struct trace_array *tr, int set);
+# define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
+#else
+static inline int irqsoff_display_graph(struct trace_array *tr, int set)
+{
+       return -EINVAL;
+}
+# define is_graph(tr) false
 #endif
-       { } /* Empty entry */
-};
-
-static struct tracer_flags tracer_flags = {
-       .val  = 0,
-       .opts = trace_opts,
-};
-
-#define is_graph() (tracer_flags.val & TRACE_DISPLAY_GRAPH)
 
 /*
  * Sequence count - we record it when starting a measurement and
@@ -152,15 +145,11 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-static int
-irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
+static int irqsoff_display_graph(struct trace_array *tr, int set)
 {
        int cpu;
 
-       if (!(bit & TRACE_DISPLAY_GRAPH))
-               return -EINVAL;
-
-       if (!(is_graph() ^ set))
+       if (!(is_graph(tr) ^ set))
                return 0;
 
        stop_irqsoff_tracer(irqsoff_trace, !set);
@@ -209,7 +198,7 @@ static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
 
 static void irqsoff_trace_open(struct trace_iterator *iter)
 {
-       if (is_graph())
+       if (is_graph(iter->tr))
                graph_trace_open(iter);
 
 }
@@ -231,7 +220,7 @@ static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
         * In graph mode call the graph tracer output function,
         * otherwise go with the TRACE_FN event handler
         */
-       if (is_graph())
+       if (is_graph(iter->tr))
                return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
 
        return TRACE_TYPE_UNHANDLED;
@@ -239,7 +228,9 @@ static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
 
 static void irqsoff_print_header(struct seq_file *s)
 {
-       if (is_graph())
+       struct trace_array *tr = irqsoff_trace;
+
+       if (is_graph(tr))
                print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
        else
                trace_default_header(s);
@@ -250,7 +241,7 @@ __trace_function(struct trace_array *tr,
                 unsigned long ip, unsigned long parent_ip,
                 unsigned long flags, int pc)
 {
-       if (is_graph())
+       if (is_graph(tr))
                trace_graph_function(tr, ip, parent_ip, flags, pc);
        else
                trace_function(tr, ip, parent_ip, flags, pc);
@@ -259,27 +250,23 @@ __trace_function(struct trace_array *tr,
 #else
 #define __trace_function trace_function
 
-static int
-irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
-{
-       return -EINVAL;
-}
-
+#ifdef CONFIG_FUNCTION_TRACER
 static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
 {
        return -1;
 }
+#endif
 
 static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
 {
        return TRACE_TYPE_UNHANDLED;
 }
 
-static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
 static void irqsoff_trace_open(struct trace_iterator *iter) { }
 static void irqsoff_trace_close(struct trace_iterator *iter) { }
 
 #ifdef CONFIG_FUNCTION_TRACER
+static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
 static void irqsoff_print_header(struct seq_file *s)
 {
        trace_default_header(s);
@@ -295,16 +282,16 @@ static void irqsoff_print_header(struct seq_file *s)
 /*
  * Should this new latency be reported/recorded?
  */
-static int report_latency(struct trace_array *tr, cycle_t delta)
+static bool report_latency(struct trace_array *tr, cycle_t delta)
 {
        if (tracing_thresh) {
                if (delta < tracing_thresh)
-                       return 0;
+                       return false;
        } else {
                if (delta <= tr->max_latency)
-                       return 0;
+                       return false;
        }
-       return 1;
+       return true;
 }
 
 static void
@@ -523,12 +510,15 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
 }
 #endif /* CONFIG_PREEMPT_TRACER */
 
+#ifdef CONFIG_FUNCTION_TRACER
+static bool function_enabled;
+
 static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
 {
        int ret;
 
        /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
-       if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
+       if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
                return 0;
 
        if (graph)
@@ -556,20 +546,40 @@ static void unregister_irqsoff_function(struct trace_array *tr, int graph)
        function_enabled = false;
 }
 
-static void irqsoff_function_set(struct trace_array *tr, int set)
+static int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
 {
+       if (!(mask & TRACE_ITER_FUNCTION))
+               return 0;
+
        if (set)
-               register_irqsoff_function(tr, is_graph(), 1);
+               register_irqsoff_function(tr, is_graph(tr), 1);
        else
-               unregister_irqsoff_function(tr, is_graph());
+               unregister_irqsoff_function(tr, is_graph(tr));
+       return 1;
+}
+#else
+static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
+{
+       return 0;
+}
+static void unregister_irqsoff_function(struct trace_array *tr, int graph) { }
+static inline int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
+{
+       return 0;
 }
+#endif /* CONFIG_FUNCTION_TRACER */
 
 static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set)
 {
        struct tracer *tracer = tr->current_trace;
 
-       if (mask & TRACE_ITER_FUNCTION)
-               irqsoff_function_set(tr, set);
+       if (irqsoff_function_set(tr, mask, set))
+               return 0;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (mask & TRACE_ITER_DISPLAY_GRAPH)
+               return irqsoff_display_graph(tr, set);
+#endif
 
        return trace_keep_overwrite(tracer, mask, set);
 }
@@ -602,7 +612,7 @@ static int __irqsoff_tracer_init(struct trace_array *tr)
        if (irqsoff_busy)
                return -EBUSY;
 
-       save_flags = trace_flags;
+       save_flags = tr->trace_flags;
 
        /* non overwrite screws up the latency tracers */
        set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
@@ -618,7 +628,7 @@ static int __irqsoff_tracer_init(struct trace_array *tr)
 
        /* Only toplevel instance supports graph tracing */
        if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
-                                     is_graph())))
+                                     is_graph(tr))))
                printk(KERN_ERR "failed to start irqsoff tracer\n");
 
        irqsoff_busy = true;
@@ -630,7 +640,7 @@ static void irqsoff_tracer_reset(struct trace_array *tr)
        int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
        int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
 
-       stop_irqsoff_tracer(tr, is_graph());
+       stop_irqsoff_tracer(tr, is_graph(tr));
 
        set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
        set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
@@ -666,8 +676,6 @@ static struct tracer irqsoff_tracer __read_mostly =
        .print_max      = true,
        .print_header   = irqsoff_print_header,
        .print_line     = irqsoff_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = irqsoff_set_flag,
        .flag_changed   = irqsoff_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_irqsoff,
@@ -700,8 +708,6 @@ static struct tracer preemptoff_tracer __read_mostly =
        .print_max      = true,
        .print_header   = irqsoff_print_header,
        .print_line     = irqsoff_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = irqsoff_set_flag,
        .flag_changed   = irqsoff_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_preemptoff,
@@ -736,8 +742,6 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
        .print_max      = true,
        .print_header   = irqsoff_print_header,
        .print_line     = irqsoff_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = irqsoff_set_flag,
        .flag_changed   = irqsoff_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_preemptirqsoff,
index 3ccf5c2c1320131e5b1bc0bfe6a26b02edc402a8..57149bce6aad679567a65b95eed2b007e19b4d81 100644 (file)
@@ -21,20 +21,22 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
        /* use static because iter can be a bit big for the stack */
        static struct trace_iterator iter;
        static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
+       struct trace_array *tr;
        unsigned int old_userobj;
        int cnt = 0, cpu;
 
        trace_init_global_iter(&iter);
        iter.buffer_iter = buffer_iter;
+       tr = iter.tr;
 
        for_each_tracing_cpu(cpu) {
                atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
        }
 
-       old_userobj = trace_flags;
+       old_userobj = tr->trace_flags;
 
        /* don't look at user memory in panic mode */
-       trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
+       tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
        kdb_printf("Dumping ftrace buffer:\n");
 
@@ -82,7 +84,7 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
                kdb_printf("---------------------------------\n");
 
 out:
-       trace_flags = old_userobj;
+       tr->trace_flags = old_userobj;
 
        for_each_tracing_cpu(cpu) {
                atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
index 638e110c5bfd4061a299a1ef3a568375c015182a..2be8c4f2403d8c6f79df5cb7e5605eec01ea4a23 100644 (file)
@@ -314,7 +314,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
        entry->rw                       = *rw;
 
        if (!call_filter_check_discard(call, entry, buffer, event))
-               trace_buffer_unlock_commit(buffer, event, 0, pc);
+               trace_buffer_unlock_commit(tr, buffer, event, 0, pc);
 }
 
 void mmio_trace_rw(struct mmiotrace_rw *rw)
@@ -344,7 +344,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
        entry->map                      = *map;
 
        if (!call_filter_check_discard(call, entry, buffer, event))
-               trace_buffer_unlock_commit(buffer, event, 0, pc);
+               trace_buffer_unlock_commit(tr, buffer, event, 0, pc);
 }
 
 void mmio_trace_mapping(struct mmiotrace_map *map)
index 8e481a84aeea79b8b008900f3b6f5dbf3044ba7c..282982195e09ff40ad23f3ab1dca7e572c0ab8e6 100644 (file)
@@ -322,8 +322,8 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt,
 # define IP_FMT "%016lx"
 #endif
 
-int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
-                     unsigned long ip, unsigned long sym_flags)
+static int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
+                            unsigned long ip, unsigned long sym_flags)
 {
        struct file *file = NULL;
        unsigned long vmstart = 0;
@@ -354,50 +354,6 @@ int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
        return !trace_seq_has_overflowed(s);
 }
 
-int
-seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
-                     unsigned long sym_flags)
-{
-       struct mm_struct *mm = NULL;
-       unsigned int i;
-
-       if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
-               struct task_struct *task;
-               /*
-                * we do the lookup on the thread group leader,
-                * since individual threads might have already quit!
-                */
-               rcu_read_lock();
-               task = find_task_by_vpid(entry->tgid);
-               if (task)
-                       mm = get_task_mm(task);
-               rcu_read_unlock();
-       }
-
-       for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
-               unsigned long ip = entry->caller[i];
-
-               if (ip == ULONG_MAX || trace_seq_has_overflowed(s))
-                       break;
-
-               trace_seq_puts(s, " => ");
-
-               if (!ip) {
-                       trace_seq_puts(s, "??");
-                       trace_seq_putc(s, '\n');
-                       continue;
-               }
-
-               seq_print_user_ip(s, mm, ip, sym_flags);
-               trace_seq_putc(s, '\n');
-       }
-
-       if (mm)
-               mmput(mm);
-
-       return !trace_seq_has_overflowed(s);
-}
-
 int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
 {
@@ -520,7 +476,8 @@ char trace_find_mark(unsigned long long d)
 static int
 lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
 {
-       unsigned long verbose = trace_flags & TRACE_ITER_VERBOSE;
+       struct trace_array *tr = iter->tr;
+       unsigned long verbose = tr->trace_flags & TRACE_ITER_VERBOSE;
        unsigned long in_ns = iter->iter_flags & TRACE_FILE_TIME_IN_NS;
        unsigned long long abs_ts = iter->ts - iter->trace_buffer->time_start;
        unsigned long long rel_ts = next_ts - iter->ts;
@@ -563,6 +520,7 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
 
 int trace_print_context(struct trace_iterator *iter)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry = iter->ent;
        unsigned long long t;
@@ -574,7 +532,7 @@ int trace_print_context(struct trace_iterator *iter)
        trace_seq_printf(s, "%16s-%-5d [%03d] ",
                               comm, entry->pid, iter->cpu);
 
-       if (trace_flags & TRACE_ITER_IRQ_INFO)
+       if (tr->trace_flags & TRACE_ITER_IRQ_INFO)
                trace_print_lat_fmt(s, entry);
 
        if (iter->iter_flags & TRACE_FILE_TIME_IN_NS) {
@@ -590,14 +548,15 @@ int trace_print_context(struct trace_iterator *iter)
 
 int trace_print_lat_context(struct trace_iterator *iter)
 {
-       u64 next_ts;
+       struct trace_array *tr = iter->tr;
        /* trace_find_next_entry will reset ent_size */
        int ent_size = iter->ent_size;
        struct trace_seq *s = &iter->seq;
+       u64 next_ts;
        struct trace_entry *entry = iter->ent,
                           *next_entry = trace_find_next_entry(iter, NULL,
                                                               &next_ts);
-       unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
+       unsigned long verbose = (tr->trace_flags & TRACE_ITER_VERBOSE);
 
        /* Restore the original ent_size */
        iter->ent_size = ent_size;
@@ -1079,13 +1038,49 @@ static struct trace_event trace_stack_event = {
 static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
                                                int flags, struct trace_event *event)
 {
+       struct trace_array *tr = iter->tr;
        struct userstack_entry *field;
        struct trace_seq *s = &iter->seq;
+       struct mm_struct *mm = NULL;
+       unsigned int i;
 
        trace_assign_type(field, iter->ent);
 
        trace_seq_puts(s, "<user stack trace>\n");
-       seq_print_userip_objs(field, s, flags);
+
+       if (tr->trace_flags & TRACE_ITER_SYM_USEROBJ) {
+               struct task_struct *task;
+               /*
+                * we do the lookup on the thread group leader,
+                * since individual threads might have already quit!
+                */
+               rcu_read_lock();
+               task = find_task_by_vpid(field->tgid);
+               if (task)
+                       mm = get_task_mm(task);
+               rcu_read_unlock();
+       }
+
+       for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
+               unsigned long ip = field->caller[i];
+
+               if (ip == ULONG_MAX || trace_seq_has_overflowed(s))
+                       break;
+
+               trace_seq_puts(s, " => ");
+
+               if (!ip) {
+                       trace_seq_puts(s, "??");
+                       trace_seq_putc(s, '\n');
+                       continue;
+               }
+
+               seq_print_user_ip(s, mm, ip, flags);
+               trace_seq_putc(s, '\n');
+       }
+
+       if (mm)
+               mmput(mm);
 
        return trace_handle_return(s);
 }
index 4cbfe85b99c80a5a8e245dc2d8c3afee26f7009a..fabc49bcd49398336a0c5397b9a87a58ab85a51d 100644 (file)
@@ -14,10 +14,6 @@ trace_print_printk_msg_only(struct trace_iterator *iter);
 extern int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip,
                unsigned long sym_flags);
-extern int seq_print_userip_objs(const struct userstack_entry *entry,
-                                struct trace_seq *s, unsigned long sym_flags);
-extern int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
-                            unsigned long ip, unsigned long sym_flags);
 
 extern int trace_print_context(struct trace_iterator *iter);
 extern int trace_print_lat_context(struct trace_iterator *iter);
index 36c1455b7567ee11f2305cc71b2aa9f48c2a0ae1..1c2b28536feb8113a408b2335c38fb0a0c4272e1 100644 (file)
@@ -178,6 +178,12 @@ static inline void format_mod_start(void) { }
 static inline void format_mod_stop(void) { }
 #endif /* CONFIG_MODULES */
 
+static bool __read_mostly trace_printk_enabled = true;
+
+void trace_printk_control(bool enabled)
+{
+       trace_printk_enabled = enabled;
+}
 
 __initdata_or_module static
 struct notifier_block module_trace_bprintk_format_nb = {
@@ -192,7 +198,7 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...)
        if (unlikely(!fmt))
                return 0;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!trace_printk_enabled)
                return 0;
 
        va_start(ap, fmt);
@@ -207,7 +213,7 @@ int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
        if (unlikely(!fmt))
                return 0;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!trace_printk_enabled)
                return 0;
 
        return trace_vbprintk(ip, fmt, ap);
@@ -219,7 +225,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...)
        int ret;
        va_list ap;
 
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!trace_printk_enabled)
                return 0;
 
        va_start(ap, fmt);
@@ -231,7 +237,7 @@ EXPORT_SYMBOL_GPL(__trace_printk);
 
 int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
 {
-       if (!(trace_flags & TRACE_ITER_PRINTK))
+       if (!trace_printk_enabled)
                return 0;
 
        return trace_vprintk(ip, fmt, ap);
index b98dee914542491d1441eb3c22c97babb24e695f..f6398db0911424cca72031a7a5831d505fae71b7 100644 (file)
@@ -302,15 +302,15 @@ static nokprobe_inline void call_fetch(struct fetch_param *fprm,
 }
 
 /* Check the name is good for event/group/fields */
-static inline int is_good_name(const char *name)
+static inline bool is_good_name(const char *name)
 {
        if (!isalpha(*name) && *name != '_')
-               return 0;
+               return false;
        while (*++name != '\0') {
                if (!isalpha(*name) && !isdigit(*name) && *name != '_')
-                       return 0;
+                       return false;
        }
-       return 1;
+       return true;
 }
 
 static inline struct event_file_link *
index 4bcfbac289ff9e9e6ab4d39772ad2dffd89509a8..9d4399b553a3c1e05387b55ec861214e86efa7ed 100644 (file)
@@ -34,31 +34,28 @@ static arch_spinlock_t wakeup_lock =
 
 static void wakeup_reset(struct trace_array *tr);
 static void __wakeup_reset(struct trace_array *tr);
-static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
-static void wakeup_graph_return(struct ftrace_graph_ret *trace);
 
 static int save_flags;
-static bool function_enabled;
-
-#define TRACE_DISPLAY_GRAPH     1
 
-static struct tracer_opt trace_opts[] = {
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       /* display latency trace as call graph */
-       { TRACER_OPT(display-graph, TRACE_DISPLAY_GRAPH) },
+static int wakeup_display_graph(struct trace_array *tr, int set);
+# define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
+#else
+static inline int wakeup_display_graph(struct trace_array *tr, int set)
+{
+       return 0;
+}
+# define is_graph(tr) false
 #endif
-       { } /* Empty entry */
-};
-
-static struct tracer_flags tracer_flags = {
-       .val  = 0,
-       .opts = trace_opts,
-};
 
-#define is_graph() (tracer_flags.val & TRACE_DISPLAY_GRAPH)
 
 #ifdef CONFIG_FUNCTION_TRACER
 
+static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
+static void wakeup_graph_return(struct ftrace_graph_ret *trace);
+
+static bool function_enabled;
+
 /*
  * Prologue for the wakeup function tracers.
  *
@@ -128,14 +125,13 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip,
        atomic_dec(&data->disabled);
        preempt_enable_notrace();
 }
-#endif /* CONFIG_FUNCTION_TRACER */
 
 static int register_wakeup_function(struct trace_array *tr, int graph, int set)
 {
        int ret;
 
        /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
-       if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
+       if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
                return 0;
 
        if (graph)
@@ -163,20 +159,40 @@ static void unregister_wakeup_function(struct trace_array *tr, int graph)
        function_enabled = false;
 }
 
-static void wakeup_function_set(struct trace_array *tr, int set)
+static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
 {
+       if (!(mask & TRACE_ITER_FUNCTION))
+               return 0;
+
        if (set)
-               register_wakeup_function(tr, is_graph(), 1);
+               register_wakeup_function(tr, is_graph(tr), 1);
        else
-               unregister_wakeup_function(tr, is_graph());
+               unregister_wakeup_function(tr, is_graph(tr));
+       return 1;
+}
+#else
+static int register_wakeup_function(struct trace_array *tr, int graph, int set)
+{
+       return 0;
+}
+static void unregister_wakeup_function(struct trace_array *tr, int graph) { }
+static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
+{
+       return 0;
 }
+#endif /* CONFIG_FUNCTION_TRACER */
 
 static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set)
 {
        struct tracer *tracer = tr->current_trace;
 
-       if (mask & TRACE_ITER_FUNCTION)
-               wakeup_function_set(tr, set);
+       if (wakeup_function_set(tr, mask, set))
+               return 0;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (mask & TRACE_ITER_DISPLAY_GRAPH)
+               return wakeup_display_graph(tr, set);
+#endif
 
        return trace_keep_overwrite(tracer, mask, set);
 }
@@ -203,14 +219,9 @@ static void stop_func_tracer(struct trace_array *tr, int graph)
 }
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-static int
-wakeup_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
+static int wakeup_display_graph(struct trace_array *tr, int set)
 {
-
-       if (!(bit & TRACE_DISPLAY_GRAPH))
-               return -EINVAL;
-
-       if (!(is_graph() ^ set))
+       if (!(is_graph(tr) ^ set))
                return 0;
 
        stop_func_tracer(tr, !set);
@@ -259,7 +270,7 @@ static void wakeup_graph_return(struct ftrace_graph_ret *trace)
 
 static void wakeup_trace_open(struct trace_iterator *iter)
 {
-       if (is_graph())
+       if (is_graph(iter->tr))
                graph_trace_open(iter);
 }
 
@@ -279,7 +290,7 @@ static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
         * In graph mode call the graph tracer output function,
         * otherwise go with the TRACE_FN event handler
         */
-       if (is_graph())
+       if (is_graph(iter->tr))
                return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
 
        return TRACE_TYPE_UNHANDLED;
@@ -287,7 +298,7 @@ static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
 
 static void wakeup_print_header(struct seq_file *s)
 {
-       if (is_graph())
+       if (is_graph(wakeup_trace))
                print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
        else
                trace_default_header(s);
@@ -298,7 +309,7 @@ __trace_function(struct trace_array *tr,
                 unsigned long ip, unsigned long parent_ip,
                 unsigned long flags, int pc)
 {
-       if (is_graph())
+       if (is_graph(tr))
                trace_graph_function(tr, ip, parent_ip, flags, pc);
        else
                trace_function(tr, ip, parent_ip, flags, pc);
@@ -306,27 +317,20 @@ __trace_function(struct trace_array *tr,
 #else
 #define __trace_function trace_function
 
-static int
-wakeup_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
-{
-       return -EINVAL;
-}
-
-static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
-{
-       return -1;
-}
-
 static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
 {
        return TRACE_TYPE_UNHANDLED;
 }
 
-static void wakeup_graph_return(struct ftrace_graph_ret *trace) { }
 static void wakeup_trace_open(struct trace_iterator *iter) { }
 static void wakeup_trace_close(struct trace_iterator *iter) { }
 
 #ifdef CONFIG_FUNCTION_TRACER
+static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
+{
+       return -1;
+}
+static void wakeup_graph_return(struct ftrace_graph_ret *trace) { }
 static void wakeup_print_header(struct seq_file *s)
 {
        trace_default_header(s);
@@ -342,16 +346,16 @@ static void wakeup_print_header(struct seq_file *s)
 /*
  * Should this new latency be reported/recorded?
  */
-static int report_latency(struct trace_array *tr, cycle_t delta)
+static bool report_latency(struct trace_array *tr, cycle_t delta)
 {
        if (tracing_thresh) {
                if (delta < tracing_thresh)
-                       return 0;
+                       return false;
        } else {
                if (delta <= tr->max_latency)
-                       return 0;
+                       return false;
        }
-       return 1;
+       return true;
 }
 
 static void
@@ -388,7 +392,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
        entry->next_cpu = task_cpu(next);
 
        if (!call_filter_check_discard(call, entry, buffer, event))
-               trace_buffer_unlock_commit(buffer, event, flags, pc);
+               trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
 }
 
 static void
@@ -416,7 +420,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        entry->next_cpu                 = task_cpu(wakee);
 
        if (!call_filter_check_discard(call, entry, buffer, event))
-               trace_buffer_unlock_commit(buffer, event, flags, pc);
+               trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
 }
 
 static void notrace
@@ -635,7 +639,7 @@ static void start_wakeup_tracer(struct trace_array *tr)
         */
        smp_wmb();
 
-       if (start_func_tracer(tr, is_graph()))
+       if (start_func_tracer(tr, is_graph(tr)))
                printk(KERN_ERR "failed to start wakeup tracer\n");
 
        return;
@@ -648,7 +652,7 @@ fail_deprobe:
 static void stop_wakeup_tracer(struct trace_array *tr)
 {
        tracer_enabled = 0;
-       stop_func_tracer(tr, is_graph());
+       stop_func_tracer(tr, is_graph(tr));
        unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
        unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
        unregister_trace_sched_wakeup(probe_wakeup, NULL);
@@ -659,7 +663,7 @@ static bool wakeup_busy;
 
 static int __wakeup_tracer_init(struct trace_array *tr)
 {
-       save_flags = trace_flags;
+       save_flags = tr->trace_flags;
 
        /* non overwrite screws up the latency tracers */
        set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
@@ -740,8 +744,6 @@ static struct tracer wakeup_tracer __read_mostly =
        .print_max      = true,
        .print_header   = wakeup_print_header,
        .print_line     = wakeup_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = wakeup_set_flag,
        .flag_changed   = wakeup_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
@@ -762,8 +764,6 @@ static struct tracer wakeup_rt_tracer __read_mostly =
        .print_max      = true,
        .print_header   = wakeup_print_header,
        .print_line     = wakeup_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = wakeup_set_flag,
        .flag_changed   = wakeup_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
@@ -784,8 +784,6 @@ static struct tracer wakeup_dl_tracer __read_mostly =
        .print_max      = true,
        .print_header   = wakeup_print_header,
        .print_line     = wakeup_print_line,
-       .flags          = &tracer_flags,
-       .set_flag       = wakeup_set_flag,
        .flag_changed   = wakeup_flag_changed,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
index 8abf1ba18085742af78176dbc514095a47643c9c..dda9e6742950305f36fbe920f9fe0c6f68d83fbf 100644 (file)
 
 #include "trace.h"
 
-#define STACK_TRACE_ENTRIES 500
-
 static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] =
         { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX };
-static unsigned stack_dump_index[STACK_TRACE_ENTRIES];
+unsigned stack_trace_index[STACK_TRACE_ENTRIES];
 
 /*
  * Reserve one entry for the passed in ip. This will allow
  * us to remove most or all of the stack size overhead
  * added by the stack tracer itself.
  */
-static struct stack_trace max_stack_trace = {
+struct stack_trace stack_trace_max = {
        .max_entries            = STACK_TRACE_ENTRIES - 1,
        .entries                = &stack_dump_trace[0],
 };
 
-static unsigned long max_stack_size;
-static arch_spinlock_t max_stack_lock =
+unsigned long stack_trace_max_size;
+arch_spinlock_t stack_trace_max_lock =
        (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
 
 static DEFINE_PER_CPU(int, trace_active);
@@ -42,30 +40,38 @@ static DEFINE_MUTEX(stack_sysctl_mutex);
 int stack_tracer_enabled;
 static int last_stack_tracer_enabled;
 
-static inline void print_max_stack(void)
+void stack_trace_print(void)
 {
        long i;
        int size;
 
        pr_emerg("        Depth    Size   Location    (%d entries)\n"
                           "        -----    ----   --------\n",
-                          max_stack_trace.nr_entries);
+                          stack_trace_max.nr_entries);
 
-       for (i = 0; i < max_stack_trace.nr_entries; i++) {
+       for (i = 0; i < stack_trace_max.nr_entries; i++) {
                if (stack_dump_trace[i] == ULONG_MAX)
                        break;
-               if (i+1 == max_stack_trace.nr_entries ||
+               if (i+1 == stack_trace_max.nr_entries ||
                                stack_dump_trace[i+1] == ULONG_MAX)
-                       size = stack_dump_index[i];
+                       size = stack_trace_index[i];
                else
-                       size = stack_dump_index[i] - stack_dump_index[i+1];
+                       size = stack_trace_index[i] - stack_trace_index[i+1];
 
-               pr_emerg("%3ld) %8d   %5d   %pS\n", i, stack_dump_index[i],
+               pr_emerg("%3ld) %8d   %5d   %pS\n", i, stack_trace_index[i],
                                size, (void *)stack_dump_trace[i]);
        }
 }
 
-static inline void
+/*
+ * When arch-specific code overides this function, the following
+ * data should be filled up, assuming stack_trace_max_lock is held to
+ * prevent concurrent updates.
+ *     stack_trace_index[]
+ *     stack_trace_max
+ *     stack_trace_max_size
+ */
+void __weak
 check_stack(unsigned long ip, unsigned long *stack)
 {
        unsigned long this_size, flags; unsigned long *p, *top, *start;
@@ -78,7 +84,7 @@ check_stack(unsigned long ip, unsigned long *stack)
        /* Remove the frame of the tracer */
        this_size -= frame_size;
 
-       if (this_size <= max_stack_size)
+       if (this_size <= stack_trace_max_size)
                return;
 
        /* we do not handle interrupt stacks yet */
@@ -90,7 +96,7 @@ check_stack(unsigned long ip, unsigned long *stack)
                return;
 
        local_irq_save(flags);
-       arch_spin_lock(&max_stack_lock);
+       arch_spin_lock(&stack_trace_max_lock);
 
        /*
         * RCU may not be watching, make it see us.
@@ -103,18 +109,18 @@ check_stack(unsigned long ip, unsigned long *stack)
                this_size -= tracer_frame;
 
        /* a race could have already updated it */
-       if (this_size <= max_stack_size)
+       if (this_size <= stack_trace_max_size)
                goto out;
 
-       max_stack_size = this_size;
+       stack_trace_max_size = this_size;
 
-       max_stack_trace.nr_entries = 0;
-       max_stack_trace.skip = 3;
+       stack_trace_max.nr_entries = 0;
+       stack_trace_max.skip = 3;
 
-       save_stack_trace(&max_stack_trace);
+       save_stack_trace(&stack_trace_max);
 
        /* Skip over the overhead of the stack tracer itself */
-       for (i = 0; i < max_stack_trace.nr_entries; i++) {
+       for (i = 0; i < stack_trace_max.nr_entries; i++) {
                if (stack_dump_trace[i] == ip)
                        break;
        }
@@ -134,18 +140,18 @@ check_stack(unsigned long ip, unsigned long *stack)
         * loop will only happen once. This code only takes place
         * on a new max, so it is far from a fast path.
         */
-       while (i < max_stack_trace.nr_entries) {
+       while (i < stack_trace_max.nr_entries) {
                int found = 0;
 
-               stack_dump_index[x] = this_size;
+               stack_trace_index[x] = this_size;
                p = start;
 
-               for (; p < top && i < max_stack_trace.nr_entries; p++) {
+               for (; p < top && i < stack_trace_max.nr_entries; p++) {
                        if (stack_dump_trace[i] == ULONG_MAX)
                                break;
                        if (*p == stack_dump_trace[i]) {
                                stack_dump_trace[x] = stack_dump_trace[i++];
-                               this_size = stack_dump_index[x++] =
+                               this_size = stack_trace_index[x++] =
                                        (top - p) * sizeof(unsigned long);
                                found = 1;
                                /* Start the search from here */
@@ -160,7 +166,7 @@ check_stack(unsigned long ip, unsigned long *stack)
                                if (unlikely(!tracer_frame)) {
                                        tracer_frame = (p - stack) *
                                                sizeof(unsigned long);
-                                       max_stack_size -= tracer_frame;
+                                       stack_trace_max_size -= tracer_frame;
                                }
                        }
                }
@@ -169,18 +175,18 @@ check_stack(unsigned long ip, unsigned long *stack)
                        i++;
        }
 
-       max_stack_trace.nr_entries = x;
+       stack_trace_max.nr_entries = x;
        for (; x < i; x++)
                stack_dump_trace[x] = ULONG_MAX;
 
        if (task_stack_end_corrupted(current)) {
-               print_max_stack();
+               stack_trace_print();
                BUG();
        }
 
  out:
        rcu_irq_exit();
-       arch_spin_unlock(&max_stack_lock);
+       arch_spin_unlock(&stack_trace_max_lock);
        local_irq_restore(flags);
 }
 
@@ -251,9 +257,9 @@ stack_max_size_write(struct file *filp, const char __user *ubuf,
        cpu = smp_processor_id();
        per_cpu(trace_active, cpu)++;
 
-       arch_spin_lock(&max_stack_lock);
+       arch_spin_lock(&stack_trace_max_lock);
        *ptr = val;
-       arch_spin_unlock(&max_stack_lock);
+       arch_spin_unlock(&stack_trace_max_lock);
 
        per_cpu(trace_active, cpu)--;
        local_irq_restore(flags);
@@ -273,7 +279,7 @@ __next(struct seq_file *m, loff_t *pos)
 {
        long n = *pos - 1;
 
-       if (n > max_stack_trace.nr_entries || stack_dump_trace[n] == ULONG_MAX)
+       if (n > stack_trace_max.nr_entries || stack_dump_trace[n] == ULONG_MAX)
                return NULL;
 
        m->private = (void *)n;
@@ -296,7 +302,7 @@ static void *t_start(struct seq_file *m, loff_t *pos)
        cpu = smp_processor_id();
        per_cpu(trace_active, cpu)++;
 
-       arch_spin_lock(&max_stack_lock);
+       arch_spin_lock(&stack_trace_max_lock);
 
        if (*pos == 0)
                return SEQ_START_TOKEN;
@@ -308,7 +314,7 @@ static void t_stop(struct seq_file *m, void *p)
 {
        int cpu;
 
-       arch_spin_unlock(&max_stack_lock);
+       arch_spin_unlock(&stack_trace_max_lock);
 
        cpu = smp_processor_id();
        per_cpu(trace_active, cpu)--;
@@ -343,9 +349,9 @@ static int t_show(struct seq_file *m, void *v)
                seq_printf(m, "        Depth    Size   Location"
                           "    (%d entries)\n"
                           "        -----    ----   --------\n",
-                          max_stack_trace.nr_entries);
+                          stack_trace_max.nr_entries);
 
-               if (!stack_tracer_enabled && !max_stack_size)
+               if (!stack_tracer_enabled && !stack_trace_max_size)
                        print_disabled(m);
 
                return 0;
@@ -353,17 +359,17 @@ static int t_show(struct seq_file *m, void *v)
 
        i = *(long *)v;
 
-       if (i >= max_stack_trace.nr_entries ||
+       if (i >= stack_trace_max.nr_entries ||
            stack_dump_trace[i] == ULONG_MAX)
                return 0;
 
-       if (i+1 == max_stack_trace.nr_entries ||
+       if (i+1 == stack_trace_max.nr_entries ||
            stack_dump_trace[i+1] == ULONG_MAX)
-               size = stack_dump_index[i];
+               size = stack_trace_index[i];
        else
-               size = stack_dump_index[i] - stack_dump_index[i+1];
+               size = stack_trace_index[i] - stack_trace_index[i+1];
 
-       seq_printf(m, "%3ld) %8d   %5d   ", i, stack_dump_index[i], size);
+       seq_printf(m, "%3ld) %8d   %5d   ", i, stack_trace_index[i], size);
 
        trace_lookup_stack(m, i);
 
@@ -453,7 +459,7 @@ static __init int stack_trace_init(void)
                return 0;
 
        trace_create_file("stack_max_size", 0644, d_tracer,
-                       &max_stack_size, &stack_max_size_fops);
+                       &stack_trace_max_size, &stack_max_size_fops);
 
        trace_create_file("stack_trace", 0444, d_tracer,
                        NULL, &stack_trace_fops);
index 7d567a4b9fa7b1cb6930c165b86f79a136b09e17..0655afbea83f596ded953d6017e0f25a640bc073 100644 (file)
@@ -110,6 +110,7 @@ static enum print_line_t
 print_syscall_enter(struct trace_iterator *iter, int flags,
                    struct trace_event *event)
 {
+       struct trace_array *tr = iter->tr;
        struct trace_seq *s = &iter->seq;
        struct trace_entry *ent = iter->ent;
        struct syscall_trace_enter *trace;
@@ -136,7 +137,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags,
                        goto end;
 
                /* parameter types */
-               if (trace_flags & TRACE_ITER_VERBOSE)
+               if (tr->trace_flags & TRACE_ITER_VERBOSE)
                        trace_seq_printf(s, "%s ", entry->types[i]);
 
                /* parameter values */
index 3490407dc7b7fefc697b8284375ab315c1df02f0..ecd536de603a1b70a34f75082869dc87046d661d 100644 (file)
@@ -91,11 +91,13 @@ static void debug_print_probes(struct tracepoint_func *funcs)
                printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func);
 }
 
-static struct tracepoint_func *func_add(struct tracepoint_func **funcs,
-               struct tracepoint_func *tp_func)
+static struct tracepoint_func *
+func_add(struct tracepoint_func **funcs, struct tracepoint_func *tp_func,
+        int prio)
 {
-       int nr_probes = 0;
        struct tracepoint_func *old, *new;
+       int nr_probes = 0;
+       int pos = -1;
 
        if (WARN_ON(!tp_func->func))
                return ERR_PTR(-EINVAL);
@@ -104,18 +106,33 @@ static struct tracepoint_func *func_add(struct tracepoint_func **funcs,
        old = *funcs;
        if (old) {
                /* (N -> N+1), (N != 0, 1) probes */
-               for (nr_probes = 0; old[nr_probes].func; nr_probes++)
+               for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
+                       /* Insert before probes of lower priority */
+                       if (pos < 0 && old[nr_probes].prio < prio)
+                               pos = nr_probes;
                        if (old[nr_probes].func == tp_func->func &&
                            old[nr_probes].data == tp_func->data)
                                return ERR_PTR(-EEXIST);
+               }
        }
        /* + 2 : one for new probe, one for NULL func */
        new = allocate_probes(nr_probes + 2);
        if (new == NULL)
                return ERR_PTR(-ENOMEM);
-       if (old)
-               memcpy(new, old, nr_probes * sizeof(struct tracepoint_func));
-       new[nr_probes] = *tp_func;
+       if (old) {
+               if (pos < 0) {
+                       pos = nr_probes;
+                       memcpy(new, old, nr_probes * sizeof(struct tracepoint_func));
+               } else {
+                       /* Copy higher priority probes ahead of the new probe */
+                       memcpy(new, old, pos * sizeof(struct tracepoint_func));
+                       /* Copy the rest after it. */
+                       memcpy(new + pos + 1, old + pos,
+                              (nr_probes - pos) * sizeof(struct tracepoint_func));
+               }
+       } else
+               pos = 0;
+       new[pos] = *tp_func;
        new[nr_probes + 1].func = NULL;
        *funcs = new;
        debug_print_probes(*funcs);
@@ -174,7 +191,7 @@ static void *func_remove(struct tracepoint_func **funcs,
  * Add the probe function to a tracepoint.
  */
 static int tracepoint_add_func(struct tracepoint *tp,
-               struct tracepoint_func *func)
+                              struct tracepoint_func *func, int prio)
 {
        struct tracepoint_func *old, *tp_funcs;
 
@@ -183,7 +200,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
 
        tp_funcs = rcu_dereference_protected(tp->funcs,
                        lockdep_is_held(&tracepoints_mutex));
-       old = func_add(&tp_funcs, func);
+       old = func_add(&tp_funcs, func, prio);
        if (IS_ERR(old)) {
                WARN_ON_ONCE(1);
                return PTR_ERR(old);
@@ -240,6 +257,7 @@ static int tracepoint_remove_func(struct tracepoint *tp,
  * @tp: tracepoint
  * @probe: probe handler
  * @data: tracepoint data
+ * @prio: priority of this function over other registered functions
  *
  * Returns 0 if ok, error value on error.
  * Note: if @tp is within a module, the caller is responsible for
@@ -247,7 +265,8 @@ static int tracepoint_remove_func(struct tracepoint *tp,
  * performed either with a tracepoint module going notifier, or from
  * within module exit functions.
  */
-int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
+int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe,
+                                  void *data, int prio)
 {
        struct tracepoint_func tp_func;
        int ret;
@@ -255,10 +274,30 @@ int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
        mutex_lock(&tracepoints_mutex);
        tp_func.func = probe;
        tp_func.data = data;
-       ret = tracepoint_add_func(tp, &tp_func);
+       tp_func.prio = prio;
+       ret = tracepoint_add_func(tp, &tp_func, prio);
        mutex_unlock(&tracepoints_mutex);
        return ret;
 }
+EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio);
+
+/**
+ * tracepoint_probe_register -  Connect a probe to a tracepoint
+ * @tp: tracepoint
+ * @probe: probe handler
+ * @data: tracepoint data
+ * @prio: priority of this function over other registered functions
+ *
+ * Returns 0 if ok, error value on error.
+ * Note: if @tp is within a module, the caller is responsible for
+ * unregistering the probe before the module is gone. This can be
+ * performed either with a tracepoint module going notifier, or from
+ * within module exit functions.
+ */
+int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
+{
+       return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO);
+}
 EXPORT_SYMBOL_GPL(tracepoint_probe_register);
 
 /**
index a89d041592c8bfa7b092c382962a4085560f5b1a..b90e255c2a680c20bccf2b7f4a9972af250cbd32 100644 (file)
@@ -19,7 +19,7 @@
  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  * MA 02111-1307, USA. */
 
-#include <asm-generic/bitops/count_zeros.h>
+#include <linux/count_zeros.h>
 
 /* You have to define the following before including this file:
  *
index c7e0a705eecfb1c389dcef39ee4f97c451728d44..3db76b8c11158f5ce2b3884898e3d2abfbd6d91a 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include <linux/bitops.h>
-#include <asm-generic/bitops/count_zeros.h>
+#include <linux/count_zeros.h>
 #include "mpi-internal.h"
 
 #define MAX_EXTERN_MPI_BITS 16384
index e1ccc83f73d3b3cdaf0f07fd6db346d44d1d7476..c29ddebc870509e7e35b69da5cce5a7d9988542d 100644 (file)
@@ -151,7 +151,7 @@ static int start_stop_khugepaged(void)
                if (!khugepaged_thread)
                        khugepaged_thread = kthread_run(khugepaged, NULL,
                                                        "khugepaged");
-               if (unlikely(IS_ERR(khugepaged_thread))) {
+               if (IS_ERR(khugepaged_thread)) {
                        pr_err("khugepaged: kthread_run(khugepaged) failed\n");
                        err = PTR_ERR(khugepaged_thread);
                        khugepaged_thread = NULL;
index ba1210253f5ec077dc01fbd1e8fc6bf2102253ef..52b4a2f993f2c91e8fdeb82e6d826467f34ec03c 100644 (file)
@@ -655,8 +655,8 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
                return -ENOMEM;
 
        /* Create the RDMA CM ID */
-       rdma->cm_id = rdma_create_id(p9_cm_event_handler, client, RDMA_PS_TCP,
-                                    IB_QPT_RC);
+       rdma->cm_id = rdma_create_id(&init_net, p9_cm_event_handler, client,
+                                    RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(rdma->cm_id))
                goto error;
 
index 5633172b791ab98e297ba1605c34bf42e684ccfb..91a8b004dc510272e6ab09c22ccea821cb62ac49 100644 (file)
@@ -1175,7 +1175,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
                                                info, OVS_FLOW_CMD_NEW, false,
                                                ufid_flags);
 
-               if (unlikely(IS_ERR(reply))) {
+               if (IS_ERR(reply)) {
                        error = PTR_ERR(reply);
                        goto err_unlock_ovs;
                }
index a833ab7898fe7306968e4ac20553afbee6955f8b..f222885ac0c7397ed08c26106e68157d91267ff6 100644 (file)
@@ -336,7 +336,7 @@ static int rds_ib_laddr_check(struct net *net, __be32 addr)
        /* Create a CMA ID and try to bind it. This catches both
         * IB and iWARP capable NICs.
         */
-       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+       cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id))
                return PTR_ERR(cm_id);
 
index f17d095678907b588c717b48e3d4602cab401199..b3fdebb57460392ae9a751bfaae2e218ff9b6e17 100644 (file)
@@ -75,7 +75,11 @@ struct rds_ib_connect_private {
 
 struct rds_ib_send_work {
        void                    *s_op;
-       struct ib_send_wr       s_wr;
+       union {
+               struct ib_send_wr       s_wr;
+               struct ib_rdma_wr       s_rdma_wr;
+               struct ib_atomic_wr     s_atomic_wr;
+       };
        struct ib_sge           s_sge[RDS_IB_MAX_SGE];
        unsigned long           s_queued;
 };
index 2b2370e7f356f5db4d23df09356796d0649ee063..da5a7fb98c77abf0c43f0c4825657874eda89ba3 100644 (file)
@@ -668,7 +668,7 @@ int rds_ib_conn_connect(struct rds_connection *conn)
 
        /* XXX I wonder what affect the port space has */
        /* delegate cm event handler to rdma_transport */
-       ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+       ic->i_cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, conn,
                                     RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ic->i_cm_id)) {
                ret = PTR_ERR(ic->i_cm_id);
index 670882c752e9470e6016fc51b0375006f4a94780..eac30bf486d747ce5a78f001de2d65cc5fc7d891 100644 (file)
@@ -777,23 +777,23 @@ int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
        send->s_queued = jiffies;
 
        if (op->op_type == RDS_ATOMIC_TYPE_CSWP) {
-               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
-               send->s_wr.wr.atomic.compare_add = op->op_m_cswp.compare;
-               send->s_wr.wr.atomic.swap = op->op_m_cswp.swap;
-               send->s_wr.wr.atomic.compare_add_mask = op->op_m_cswp.compare_mask;
-               send->s_wr.wr.atomic.swap_mask = op->op_m_cswp.swap_mask;
+               send->s_atomic_wr.wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
+               send->s_atomic_wr.compare_add = op->op_m_cswp.compare;
+               send->s_atomic_wr.swap = op->op_m_cswp.swap;
+               send->s_atomic_wr.compare_add_mask = op->op_m_cswp.compare_mask;
+               send->s_atomic_wr.swap_mask = op->op_m_cswp.swap_mask;
        } else { /* FADD */
-               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
-               send->s_wr.wr.atomic.compare_add = op->op_m_fadd.add;
-               send->s_wr.wr.atomic.swap = 0;
-               send->s_wr.wr.atomic.compare_add_mask = op->op_m_fadd.nocarry_mask;
-               send->s_wr.wr.atomic.swap_mask = 0;
+               send->s_atomic_wr.wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
+               send->s_atomic_wr.compare_add = op->op_m_fadd.add;
+               send->s_atomic_wr.swap = 0;
+               send->s_atomic_wr.compare_add_mask = op->op_m_fadd.nocarry_mask;
+               send->s_atomic_wr.swap_mask = 0;
        }
        nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify);
-       send->s_wr.num_sge = 1;
-       send->s_wr.next = NULL;
-       send->s_wr.wr.atomic.remote_addr = op->op_remote_addr;
-       send->s_wr.wr.atomic.rkey = op->op_rkey;
+       send->s_atomic_wr.wr.num_sge = 1;
+       send->s_atomic_wr.wr.next = NULL;
+       send->s_atomic_wr.remote_addr = op->op_remote_addr;
+       send->s_atomic_wr.rkey = op->op_rkey;
        send->s_op = op;
        rds_message_addref(container_of(send->s_op, struct rds_message, atomic));
 
@@ -818,11 +818,11 @@ int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
        if (nr_sig)
                atomic_add(nr_sig, &ic->i_signaled_sends);
 
-       failed_wr = &send->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &send->s_wr, &failed_wr);
+       failed_wr = &send->s_atomic_wr.wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &send->s_atomic_wr.wr, &failed_wr);
        rdsdebug("ic %p send %p (wr %p) ret %d wr %p\n", ic,
-                send, &send->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &send->s_wr);
+                send, &send->s_atomic_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &send->s_atomic_wr.wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IB: atomic ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
@@ -831,9 +831,9 @@ int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
                goto out;
        }
 
-       if (unlikely(failed_wr != &send->s_wr)) {
+       if (unlikely(failed_wr != &send->s_atomic_wr.wr)) {
                printk(KERN_WARNING "RDS/IB: atomic ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
-               BUG_ON(failed_wr != &send->s_wr);
+               BUG_ON(failed_wr != &send->s_atomic_wr.wr);
        }
 
 out:
@@ -904,22 +904,23 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                nr_sig += rds_ib_set_wr_signal_state(ic, send, op->op_notify);
 
                send->s_wr.opcode = op->op_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
-               send->s_wr.wr.rdma.remote_addr = remote_addr;
-               send->s_wr.wr.rdma.rkey = op->op_rkey;
+               send->s_rdma_wr.remote_addr = remote_addr;
+               send->s_rdma_wr.rkey = op->op_rkey;
 
                if (num_sge > max_sge) {
-                       send->s_wr.num_sge = max_sge;
+                       send->s_rdma_wr.wr.num_sge = max_sge;
                        num_sge -= max_sge;
                } else {
-                       send->s_wr.num_sge = num_sge;
+                       send->s_rdma_wr.wr.num_sge = num_sge;
                }
 
-               send->s_wr.next = NULL;
+               send->s_rdma_wr.wr.next = NULL;
 
                if (prev)
-                       prev->s_wr.next = &send->s_wr;
+                       prev->s_rdma_wr.wr.next = &send->s_rdma_wr.wr;
 
-               for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
+               for (j = 0; j < send->s_rdma_wr.wr.num_sge &&
+                    scat != &op->op_sg[op->op_count]; j++) {
                        len = ib_sg_dma_len(ic->i_cm_id->device, scat);
                        send->s_sge[j].addr =
                                 ib_sg_dma_address(ic->i_cm_id->device, scat);
@@ -934,7 +935,9 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                }
 
                rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                       &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+                       &send->s_rdma_wr.wr,
+                       send->s_rdma_wr.wr.num_sge,
+                       send->s_rdma_wr.wr.next);
 
                prev = send;
                if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
@@ -955,11 +958,11 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
        if (nr_sig)
                atomic_add(nr_sig, &ic->i_signaled_sends);
 
-       failed_wr = &first->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       failed_wr = &first->s_rdma_wr.wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_rdma_wr.wr, &failed_wr);
        rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_wr);
+                first, &first->s_rdma_wr.wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_rdma_wr.wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
@@ -968,9 +971,9 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                goto out;
        }
 
-       if (unlikely(failed_wr != &first->s_wr)) {
+       if (unlikely(failed_wr != &first->s_rdma_wr.wr)) {
                printk(KERN_WARNING "RDS/IB: ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
-               BUG_ON(failed_wr != &first->s_wr);
+               BUG_ON(failed_wr != &first->s_rdma_wr.wr);
        }
 
 
index 3df0295c6659c305751b14e4585e2504fbb7a90f..576f1825fc55769f7242c75c771a50a6e8e5e93b 100644 (file)
@@ -223,7 +223,7 @@ static int rds_iw_laddr_check(struct net *net, __be32 addr)
        /* Create a CMA ID and try to bind it. This catches both
         * IB and iWARP capable NICs.
         */
-       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+       cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id))
                return PTR_ERR(cm_id);
 
index cbe6674e31ee52f6c9fd4380e3f0942127ede7c9..5af01d1758b3914d076088c8906d085b177febe4 100644 (file)
@@ -74,10 +74,13 @@ struct rds_iw_send_work {
        struct rm_rdma_op       *s_op;
        struct rds_iw_mapping   *s_mapping;
        struct ib_mr            *s_mr;
-       struct ib_fast_reg_page_list *s_page_list;
        unsigned char           s_remap_count;
 
-       struct ib_send_wr       s_wr;
+       union {
+               struct ib_send_wr       s_send_wr;
+               struct ib_rdma_wr       s_rdma_wr;
+               struct ib_reg_wr        s_reg_wr;
+       };
        struct ib_sge           s_sge[RDS_IW_MAX_SGE];
        unsigned long           s_queued;
 };
@@ -195,7 +198,7 @@ struct rds_iw_device {
 
 /* Magic WR_ID for ACKs */
 #define RDS_IW_ACK_WR_ID       ((u64)0xffffffffffffffffULL)
-#define RDS_IW_FAST_REG_WR_ID  ((u64)0xefefefefefefefefULL)
+#define RDS_IW_REG_WR_ID       ((u64)0xefefefefefefefefULL)
 #define RDS_IW_LOCAL_INV_WR_ID ((u64)0xdfdfdfdfdfdfdfdfULL)
 
 struct rds_iw_statistics {
index a6553a6fb2bc2e5053152b620851790379673d40..aea4c911bc765c1288adc233640e654f200f6f7f 100644 (file)
@@ -524,7 +524,7 @@ int rds_iw_conn_connect(struct rds_connection *conn)
 
        /* XXX I wonder what affect the port space has */
        /* delegate cm event handler to rdma_transport */
-       ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+       ic->i_cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, conn,
                                     RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ic->i_cm_id)) {
                ret = PTR_ERR(ic->i_cm_id);
index d3d4454ffc84c6603397976e8c027b62c3300fbe..b09a40c1adceebf170617da3826c82002b04807a 100644 (file)
@@ -47,7 +47,6 @@ struct rds_iw_mr {
        struct rdma_cm_id       *cm_id;
 
        struct ib_mr    *mr;
-       struct ib_fast_reg_page_list *page_list;
 
        struct rds_iw_mapping   mapping;
        unsigned char           remap_count;
@@ -77,8 +76,8 @@ struct rds_iw_mr_pool {
 
 static void rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all);
 static void rds_iw_mr_pool_flush_worker(struct work_struct *work);
-static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
-static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
+static int rds_iw_init_reg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
+static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
                          struct rds_iw_mr *ibmr,
                          struct scatterlist *sg, unsigned int nents);
 static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
@@ -258,19 +257,18 @@ static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg,
        sg->bytes = 0;
 }
 
-static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
-                       struct rds_iw_scatterlist *sg)
+static int rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
+                                 struct rds_iw_scatterlist *sg)
 {
        struct ib_device *dev = rds_iwdev->dev;
-       u64 *dma_pages = NULL;
-       int i, j, ret;
+       int i, ret;
 
        WARN_ON(sg->dma_len);
 
        sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
        if (unlikely(!sg->dma_len)) {
                printk(KERN_WARNING "RDS/IW: dma_map_sg failed!\n");
-               return ERR_PTR(-EBUSY);
+               return -EBUSY;
        }
 
        sg->bytes = 0;
@@ -303,31 +301,14 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
        if (sg->dma_npages > fastreg_message_size)
                goto out_unmap;
 
-       dma_pages = kmalloc(sizeof(u64) * sg->dma_npages, GFP_ATOMIC);
-       if (!dma_pages) {
-               ret = -ENOMEM;
-               goto out_unmap;
-       }
 
-       for (i = j = 0; i < sg->dma_len; ++i) {
-               unsigned int dma_len = ib_sg_dma_len(dev, &sg->list[i]);
-               u64 dma_addr = ib_sg_dma_address(dev, &sg->list[i]);
-               u64 end_addr;
 
-               end_addr = dma_addr + dma_len;
-               dma_addr &= ~PAGE_MASK;
-               for (; dma_addr < end_addr; dma_addr += PAGE_SIZE)
-                       dma_pages[j++] = dma_addr;
-               BUG_ON(j > sg->dma_npages);
-       }
-
-       return dma_pages;
+       return 0;
 
 out_unmap:
        ib_dma_unmap_sg(rds_iwdev->dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
        sg->dma_len = 0;
-       kfree(dma_pages);
-       return ERR_PTR(ret);
+       return ret;
 }
 
 
@@ -440,7 +421,7 @@ static struct rds_iw_mr *rds_iw_alloc_mr(struct rds_iw_device *rds_iwdev)
        INIT_LIST_HEAD(&ibmr->mapping.m_list);
        ibmr->mapping.m_mr = ibmr;
 
-       err = rds_iw_init_fastreg(pool, ibmr);
+       err = rds_iw_init_reg(pool, ibmr);
        if (err)
                goto out_no_cigar;
 
@@ -620,7 +601,7 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
        ibmr->cm_id = cm_id;
        ibmr->device = rds_iwdev;
 
-       ret = rds_iw_map_fastreg(rds_iwdev->mr_pool, ibmr, sg, nents);
+       ret = rds_iw_map_reg(rds_iwdev->mr_pool, ibmr, sg, nents);
        if (ret == 0)
                *key_ret = ibmr->mr->rkey;
        else
@@ -636,7 +617,7 @@ out:
 }
 
 /*
- * iWARP fastreg handling
+ * iWARP reg handling
  *
  * The life cycle of a fastreg registration is a bit different from
  * FMRs.
@@ -648,7 +629,7 @@ out:
  * This creates a bit of a problem for us, as we do not have the destination
  * IP in GET_MR, so the connection must be setup prior to the GET_MR call for
  * RDMA to be correctly setup.  If a fastreg request is present, rds_iw_xmit
- * will try to queue a LOCAL_INV (if needed) and a FAST_REG_MR work request
+ * will try to queue a LOCAL_INV (if needed) and a REG_MR work request
  * before queuing the SEND. When completions for these arrive, they are
  * dispatched to the MR has a bit set showing that RDMa can be performed.
  *
@@ -657,11 +638,10 @@ out:
  * The expectation there is that this invalidation step includes ALL
  * PREVIOUSLY FREED MRs.
  */
-static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool,
-                               struct rds_iw_mr *ibmr)
+static int rds_iw_init_reg(struct rds_iw_mr_pool *pool,
+                          struct rds_iw_mr *ibmr)
 {
        struct rds_iw_device *rds_iwdev = pool->device;
-       struct ib_fast_reg_page_list *page_list = NULL;
        struct ib_mr *mr;
        int err;
 
@@ -674,55 +654,44 @@ static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool,
                return err;
        }
 
-       /* FIXME - this is overkill, but mapping->m_sg.dma_len/mapping->m_sg.dma_npages
-        * is not filled in.
-        */
-       page_list = ib_alloc_fast_reg_page_list(rds_iwdev->dev, pool->max_message_size);
-       if (IS_ERR(page_list)) {
-               err = PTR_ERR(page_list);
-
-               printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_page_list failed (err=%d)\n", err);
-               ib_dereg_mr(mr);
-               return err;
-       }
-
-       ibmr->page_list = page_list;
        ibmr->mr = mr;
        return 0;
 }
 
-static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping)
+static int rds_iw_rdma_reg_mr(struct rds_iw_mapping *mapping)
 {
        struct rds_iw_mr *ibmr = mapping->m_mr;
-       struct ib_send_wr f_wr, *failed_wr;
-       int ret;
+       struct rds_iw_scatterlist *m_sg = &mapping->m_sg;
+       struct ib_reg_wr reg_wr;
+       struct ib_send_wr *failed_wr;
+       int ret, n;
+
+       n = ib_map_mr_sg_zbva(ibmr->mr, m_sg->list, m_sg->len, PAGE_SIZE);
+       if (unlikely(n != m_sg->len))
+               return n < 0 ? n : -EINVAL;
+
+       reg_wr.wr.next = NULL;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = RDS_IW_REG_WR_ID;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = ibmr->mr;
+       reg_wr.key = mapping->m_rkey;
+       reg_wr.access = IB_ACCESS_LOCAL_WRITE |
+                       IB_ACCESS_REMOTE_READ |
+                       IB_ACCESS_REMOTE_WRITE;
 
        /*
-        * Perform a WR for the fast_reg_mr. Each individual page
+        * Perform a WR for the reg_mr. Each individual page
         * in the sg list is added to the fast reg page list and placed
-        * inside the fast_reg_mr WR.  The key used is a rolling 8bit
+        * inside the reg_mr WR.  The key used is a rolling 8bit
         * counter, which should guarantee uniqueness.
         */
        ib_update_fast_reg_key(ibmr->mr, ibmr->remap_count++);
        mapping->m_rkey = ibmr->mr->rkey;
 
-       memset(&f_wr, 0, sizeof(f_wr));
-       f_wr.wr_id = RDS_IW_FAST_REG_WR_ID;
-       f_wr.opcode = IB_WR_FAST_REG_MR;
-       f_wr.wr.fast_reg.length = mapping->m_sg.bytes;
-       f_wr.wr.fast_reg.rkey = mapping->m_rkey;
-       f_wr.wr.fast_reg.page_list = ibmr->page_list;
-       f_wr.wr.fast_reg.page_list_len = mapping->m_sg.dma_len;
-       f_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE |
-                               IB_ACCESS_REMOTE_READ |
-                               IB_ACCESS_REMOTE_WRITE;
-       f_wr.wr.fast_reg.iova_start = 0;
-       f_wr.send_flags = IB_SEND_SIGNALED;
-
-       failed_wr = &f_wr;
-       ret = ib_post_send(ibmr->cm_id->qp, &f_wr, &failed_wr);
-       BUG_ON(failed_wr != &f_wr);
+       failed_wr = &reg_wr.wr;
+       ret = ib_post_send(ibmr->cm_id->qp, &reg_wr.wr, &failed_wr);
+       BUG_ON(failed_wr != &reg_wr.wr);
        if (ret)
                printk_ratelimited(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
                        __func__, __LINE__, ret);
@@ -754,21 +723,20 @@ out:
        return ret;
 }
 
-static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
-                       struct rds_iw_mr *ibmr,
-                       struct scatterlist *sg,
-                       unsigned int sg_len)
+static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
+                         struct rds_iw_mr *ibmr,
+                         struct scatterlist *sg,
+                         unsigned int sg_len)
 {
        struct rds_iw_device *rds_iwdev = pool->device;
        struct rds_iw_mapping *mapping = &ibmr->mapping;
        u64 *dma_pages;
-       int i, ret = 0;
+       int ret = 0;
 
        rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len);
 
-       dma_pages = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
-       if (IS_ERR(dma_pages)) {
-               ret = PTR_ERR(dma_pages);
+       ret = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
+       if (ret) {
                dma_pages = NULL;
                goto out;
        }
@@ -778,10 +746,7 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
                goto out;
        }
 
-       for (i = 0; i < mapping->m_sg.dma_npages; ++i)
-               ibmr->page_list->page_list[i] = dma_pages[i];
-
-       ret = rds_iw_rdma_build_fastreg(mapping);
+       ret = rds_iw_rdma_reg_mr(mapping);
        if (ret)
                goto out;
 
@@ -867,8 +832,6 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
 static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool,
                struct rds_iw_mr *ibmr)
 {
-       if (ibmr->page_list)
-               ib_free_fast_reg_page_list(ibmr->page_list);
        if (ibmr->mr)
                ib_dereg_mr(ibmr->mr);
 }
index 86152ec3b8879a2dcf6eb41f85fa1cd746f5cb00..e20bd503f4bd5c87363b79dbd9e3ca0e0f8e2f4d 100644 (file)
@@ -137,13 +137,13 @@ void rds_iw_send_init_ring(struct rds_iw_connection *ic)
                send->s_op = NULL;
                send->s_mapping = NULL;
 
-               send->s_wr.next = NULL;
-               send->s_wr.wr_id = i;
-               send->s_wr.sg_list = send->s_sge;
-               send->s_wr.num_sge = 1;
-               send->s_wr.opcode = IB_WR_SEND;
-               send->s_wr.send_flags = 0;
-               send->s_wr.ex.imm_data = 0;
+               send->s_send_wr.next = NULL;
+               send->s_send_wr.wr_id = i;
+               send->s_send_wr.sg_list = send->s_sge;
+               send->s_send_wr.num_sge = 1;
+               send->s_send_wr.opcode = IB_WR_SEND;
+               send->s_send_wr.send_flags = 0;
+               send->s_send_wr.ex.imm_data = 0;
 
                sge = rds_iw_data_sge(ic, send->s_sge);
                sge->lkey = 0;
@@ -159,13 +159,6 @@ void rds_iw_send_init_ring(struct rds_iw_connection *ic)
                        printk(KERN_WARNING "RDS/IW: ib_alloc_mr failed\n");
                        break;
                }
-
-               send->s_page_list = ib_alloc_fast_reg_page_list(
-                       ic->i_cm_id->device, fastreg_message_size);
-               if (IS_ERR(send->s_page_list)) {
-                       printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_page_list failed\n");
-                       break;
-               }
        }
 }
 
@@ -177,9 +170,7 @@ void rds_iw_send_clear_ring(struct rds_iw_connection *ic)
        for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
                BUG_ON(!send->s_mr);
                ib_dereg_mr(send->s_mr);
-               BUG_ON(!send->s_page_list);
-               ib_free_fast_reg_page_list(send->s_page_list);
-               if (send->s_wr.opcode == 0xdead)
+               if (send->s_send_wr.opcode == 0xdead)
                        continue;
                if (send->s_rm)
                        rds_iw_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
@@ -227,7 +218,7 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
                        continue;
                }
 
-               if (wc.opcode == IB_WC_FAST_REG_MR && wc.wr_id == RDS_IW_FAST_REG_WR_ID) {
+               if (wc.opcode == IB_WC_REG_MR && wc.wr_id == RDS_IW_REG_WR_ID) {
                        ic->i_fastreg_posted = 1;
                        continue;
                }
@@ -247,12 +238,12 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
                        send = &ic->i_sends[oldest];
 
                        /* In the error case, wc.opcode sometimes contains garbage */
-                       switch (send->s_wr.opcode) {
+                       switch (send->s_send_wr.opcode) {
                        case IB_WR_SEND:
                                if (send->s_rm)
                                        rds_iw_send_unmap_rm(ic, send, wc.status);
                                break;
-                       case IB_WR_FAST_REG_MR:
+                       case IB_WR_REG_MR:
                        case IB_WR_RDMA_WRITE:
                        case IB_WR_RDMA_READ:
                        case IB_WR_RDMA_READ_WITH_INV:
@@ -262,12 +253,12 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
                        default:
                                printk_ratelimited(KERN_NOTICE
                                                "RDS/IW: %s: unexpected opcode 0x%x in WR!\n",
-                                               __func__, send->s_wr.opcode);
+                                               __func__, send->s_send_wr.opcode);
                                break;
                        }
 
-                       send->s_wr.opcode = 0xdead;
-                       send->s_wr.num_sge = 1;
+                       send->s_send_wr.opcode = 0xdead;
+                       send->s_send_wr.num_sge = 1;
                        if (time_after(jiffies, send->s_queued + HZ/2))
                                rds_iw_stats_inc(s_iw_tx_stalled);
 
@@ -455,10 +446,10 @@ rds_iw_xmit_populate_wr(struct rds_iw_connection *ic,
 
        WARN_ON(pos != send - ic->i_sends);
 
-       send->s_wr.send_flags = send_flags;
-       send->s_wr.opcode = IB_WR_SEND;
-       send->s_wr.num_sge = 2;
-       send->s_wr.next = NULL;
+       send->s_send_wr.send_flags = send_flags;
+       send->s_send_wr.opcode = IB_WR_SEND;
+       send->s_send_wr.num_sge = 2;
+       send->s_send_wr.next = NULL;
        send->s_queued = jiffies;
        send->s_op = NULL;
 
@@ -472,7 +463,7 @@ rds_iw_xmit_populate_wr(struct rds_iw_connection *ic,
        } else {
                /* We're sending a packet with no payload. There is only
                 * one SGE */
-               send->s_wr.num_sge = 1;
+               send->s_send_wr.num_sge = 1;
                sge = &send->s_sge[0];
        }
 
@@ -672,23 +663,23 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
                 */
                if (ic->i_unsignaled_wrs-- == 0) {
                        ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
-                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
                }
 
                ic->i_unsignaled_bytes -= len;
                if (ic->i_unsignaled_bytes <= 0) {
                        ic->i_unsignaled_bytes = rds_iw_sysctl_max_unsig_bytes;
-                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
                }
 
                /*
                 * Always signal the last one if we're stopping due to flow control.
                 */
                if (flow_controlled && i == (work_alloc-1))
-                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
 
                rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                        &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+                        &send->s_send_wr, send->s_send_wr.num_sge, send->s_send_wr.next);
 
                sent += len;
                rm->data.op_dmaoff += len;
@@ -722,7 +713,7 @@ add_header:
                }
 
                if (prev)
-                       prev->s_wr.next = &send->s_wr;
+                       prev->s_send_wr.next = &send->s_send_wr;
                prev = send;
 
                pos = (pos + 1) % ic->i_send_ring.w_nr;
@@ -736,7 +727,7 @@ add_header:
        /* if we finished the message then send completion owns it */
        if (scat == &rm->data.op_sg[rm->data.op_count]) {
                prev->s_rm = ic->i_rm;
-               prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               prev->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
                ic->i_rm = NULL;
        }
 
@@ -748,11 +739,11 @@ add_header:
                rds_iw_send_add_credits(conn, credit_alloc - i);
 
        /* XXX need to worry about failed_wr and partial sends. */
-       failed_wr = &first->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       failed_wr = &first->s_send_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_send_wr, &failed_wr);
        rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_wr);
+                first, &first->s_send_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_send_wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IW: ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
@@ -770,24 +761,26 @@ out:
        return ret;
 }
 
-static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rds_iw_connection *ic, struct rds_iw_send_work *send, int nent, int len, u64 sg_addr)
+static int rds_iw_build_send_reg(struct rds_iw_send_work *send,
+                                struct scatterlist *sg,
+                                int sg_nents)
 {
-       BUG_ON(nent > send->s_page_list->max_page_list_len);
-       /*
-        * Perform a WR for the fast_reg_mr. Each individual page
-        * in the sg list is added to the fast reg page list and placed
-        * inside the fast_reg_mr WR.
-        */
-       send->s_wr.opcode = IB_WR_FAST_REG_MR;
-       send->s_wr.wr.fast_reg.length = len;
-       send->s_wr.wr.fast_reg.rkey = send->s_mr->rkey;
-       send->s_wr.wr.fast_reg.page_list = send->s_page_list;
-       send->s_wr.wr.fast_reg.page_list_len = nent;
-       send->s_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       send->s_wr.wr.fast_reg.access_flags = IB_ACCESS_REMOTE_WRITE;
-       send->s_wr.wr.fast_reg.iova_start = sg_addr;
+       int n;
+
+       n = ib_map_mr_sg(send->s_mr, sg, sg_nents, PAGE_SIZE);
+       if (unlikely(n != sg_nents))
+               return n < 0 ? n : -EINVAL;
+
+       send->s_reg_wr.wr.opcode = IB_WR_REG_MR;
+       send->s_reg_wr.wr.wr_id = 0;
+       send->s_reg_wr.wr.num_sge = 0;
+       send->s_reg_wr.mr = send->s_mr;
+       send->s_reg_wr.key = send->s_mr->rkey;
+       send->s_reg_wr.access = IB_ACCESS_REMOTE_WRITE;
 
        ib_update_fast_reg_key(send->s_mr, send->s_remap_count++);
+
+       return 0;
 }
 
 int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
@@ -808,6 +801,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
        int sent;
        int ret;
        int num_sge;
+       int sg_nents;
 
        rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
 
@@ -861,9 +855,10 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
        scat = &op->op_sg[0];
        sent = 0;
        num_sge = op->op_count;
+       sg_nents = 0;
 
        for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
-               send->s_wr.send_flags = 0;
+               send->s_rdma_wr.wr.send_flags = 0;
                send->s_queued = jiffies;
 
                /*
@@ -872,7 +867,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                 */
                if (ic->i_unsignaled_wrs-- == 0) {
                        ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
-                       send->s_wr.send_flags = IB_SEND_SIGNALED;
+                       send->s_rdma_wr.wr.send_flags = IB_SEND_SIGNALED;
                }
 
                /* To avoid the need to have the plumbing to invalidate the fastreg_mr used
@@ -880,30 +875,31 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                 * IB_WR_RDMA_READ_WITH_INV will invalidate it after the read has completed.
                 */
                if (op->op_write)
-                       send->s_wr.opcode = IB_WR_RDMA_WRITE;
+                       send->s_rdma_wr.wr.opcode = IB_WR_RDMA_WRITE;
                else
-                       send->s_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
+                       send->s_rdma_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
 
-               send->s_wr.wr.rdma.remote_addr = remote_addr;
-               send->s_wr.wr.rdma.rkey = op->op_rkey;
+               send->s_rdma_wr.remote_addr = remote_addr;
+               send->s_rdma_wr.rkey = op->op_rkey;
                send->s_op = op;
 
                if (num_sge > rds_iwdev->max_sge) {
-                       send->s_wr.num_sge = rds_iwdev->max_sge;
+                       send->s_rdma_wr.wr.num_sge = rds_iwdev->max_sge;
                        num_sge -= rds_iwdev->max_sge;
                } else
-                       send->s_wr.num_sge = num_sge;
+                       send->s_rdma_wr.wr.num_sge = num_sge;
 
-               send->s_wr.next = NULL;
+               send->s_rdma_wr.wr.next = NULL;
 
                if (prev)
-                       prev->s_wr.next = &send->s_wr;
+                       prev->s_send_wr.next = &send->s_rdma_wr.wr;
 
-               for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
+               for (j = 0; j < send->s_rdma_wr.wr.num_sge &&
+                    scat != &op->op_sg[op->op_count]; j++) {
                        len = ib_sg_dma_len(ic->i_cm_id->device, scat);
 
-                       if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV)
-                               send->s_page_list->page_list[j] = ib_sg_dma_address(ic->i_cm_id->device, scat);
+                       if (send->s_rdma_wr.wr.opcode == IB_WR_RDMA_READ_WITH_INV)
+                               sg_nents++;
                        else {
                                send->s_sge[j].addr = ib_sg_dma_address(ic->i_cm_id->device, scat);
                                send->s_sge[j].length = len;
@@ -917,15 +913,17 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
                        scat++;
                }
 
-               if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV) {
-                       send->s_wr.num_sge = 1;
+               if (send->s_rdma_wr.wr.opcode == IB_WR_RDMA_READ_WITH_INV) {
+                       send->s_rdma_wr.wr.num_sge = 1;
                        send->s_sge[0].addr = conn->c_xmit_rm->m_rs->rs_user_addr;
                        send->s_sge[0].length = conn->c_xmit_rm->m_rs->rs_user_bytes;
                        send->s_sge[0].lkey = ic->i_sends[fr_pos].s_mr->lkey;
                }
 
                rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                       &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+                       &send->s_rdma_wr,
+                       send->s_rdma_wr.wr.num_sge,
+                       send->s_rdma_wr.wr.next);
 
                prev = send;
                if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
@@ -934,7 +932,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
 
        /* if we finished the message then send completion owns it */
        if (scat == &op->op_sg[op->op_count])
-               first->s_wr.send_flags = IB_SEND_SIGNALED;
+               first->s_rdma_wr.wr.send_flags = IB_SEND_SIGNALED;
 
        if (i < work_alloc) {
                rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - i);
@@ -948,16 +946,20 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
         * fastreg_mr (or possibly a dma_mr)
         */
        if (!op->op_write) {
-               rds_iw_build_send_fastreg(rds_iwdev, ic, &ic->i_sends[fr_pos],
-                       op->op_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
+               ret = rds_iw_build_send_reg(&ic->i_sends[fr_pos],
+                                           &op->op_sg[0], sg_nents);
+               if (ret) {
+                       printk(KERN_WARNING "RDS/IW: failed to reg send mem\n");
+                       goto out;
+               }
                work_alloc++;
        }
 
-       failed_wr = &first->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       failed_wr = &first->s_rdma_wr.wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_rdma_wr.wr, &failed_wr);
        rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_wr);
+                first, &first->s_rdma_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_rdma_wr.wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IW: rdma ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
index b9b40af5345b6f42a6ac8e7baea1405ac7c20fda..9c1fed81bf0f73927cc97a09c92e66fd926f288a 100644 (file)
@@ -142,8 +142,8 @@ static int rds_rdma_listen_init(void)
        struct rdma_cm_id *cm_id;
        int ret;
 
-       cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP,
-                              IB_QPT_RC);
+       cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, NULL,
+                              RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id)) {
                ret = PTR_ERR(cm_id);
                printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
index 17bef01b9aa3e7f75328d39fc976f9e80d641e92..897c01c029cab3d5805cc56b0964c70e06f4143a 100644 (file)
@@ -4475,7 +4475,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
        }
 
        newfile = sock_alloc_file(newsock, 0, NULL);
-       if (unlikely(IS_ERR(newfile))) {
+       if (IS_ERR(newfile)) {
                put_unused_fd(retval);
                sock_release(newsock);
                return PTR_ERR(newfile);
index 9963a0b53a642f4ce600018606d1b8cb9982df9e..dd2c247c99e30a7950323c85e1ea9cb604eac218 100644 (file)
@@ -373,7 +373,7 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
 
        file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
                  &socket_file_ops);
-       if (unlikely(IS_ERR(file))) {
+       if (IS_ERR(file)) {
                /* drop dentry, keep inode */
                ihold(d_inode(path.dentry));
                path_put(&path);
@@ -1303,7 +1303,7 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
        }
 
        newfile1 = sock_alloc_file(sock1, flags, NULL);
-       if (unlikely(IS_ERR(newfile1))) {
+       if (IS_ERR(newfile1)) {
                err = PTR_ERR(newfile1);
                goto out_put_unused_both;
        }
@@ -1467,7 +1467,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
                goto out_put;
        }
        newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
-       if (unlikely(IS_ERR(newfile))) {
+       if (IS_ERR(newfile)) {
                err = PTR_ERR(newfile);
                put_unused_fd(newfd);
                sock_release(newsock);
index 5318951b3b531ca322f1a0c3639a9079d3599555..a1434447b0d6ae9a937a7d9d90c51660de8717b6 100644 (file)
@@ -151,9 +151,13 @@ __frwr_init(struct rpcrdma_mw *r, struct ib_pd *pd, struct ib_device *device,
        f->fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth);
        if (IS_ERR(f->fr_mr))
                goto out_mr_err;
-       f->fr_pgl = ib_alloc_fast_reg_page_list(device, depth);
-       if (IS_ERR(f->fr_pgl))
+
+       f->sg = kcalloc(depth, sizeof(*f->sg), GFP_KERNEL);
+       if (!f->sg)
                goto out_list_err;
+
+       sg_init_table(f->sg, depth);
+
        return 0;
 
 out_mr_err:
@@ -163,9 +167,9 @@ out_mr_err:
        return rc;
 
 out_list_err:
-       rc = PTR_ERR(f->fr_pgl);
-       dprintk("RPC:       %s: ib_alloc_fast_reg_page_list status %i\n",
-               __func__, rc);
+       rc = -ENOMEM;
+       dprintk("RPC:       %s: sg allocation failure\n",
+               __func__);
        ib_dereg_mr(f->fr_mr);
        return rc;
 }
@@ -179,7 +183,7 @@ __frwr_release(struct rpcrdma_mw *r)
        if (rc)
                dprintk("RPC:       %s: ib_dereg_mr status %i\n",
                        __func__, rc);
-       ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
+       kfree(r->r.frmr.sg);
 }
 
 static int
@@ -312,13 +316,10 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        struct rpcrdma_mw *mw;
        struct rpcrdma_frmr *frmr;
        struct ib_mr *mr;
-       struct ib_send_wr fastreg_wr, *bad_wr;
+       struct ib_reg_wr reg_wr;
+       struct ib_send_wr *bad_wr;
+       int rc, i, n, dma_nents;
        u8 key;
-       int len, pageoff;
-       int i, rc;
-       int seg_len;
-       u64 pa;
-       int page_no;
 
        mw = seg1->rl_mw;
        seg1->rl_mw = NULL;
@@ -331,64 +332,80 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
        } while (mw->r.frmr.fr_state != FRMR_IS_INVALID);
        frmr = &mw->r.frmr;
        frmr->fr_state = FRMR_IS_VALID;
+       mr = frmr->fr_mr;
 
-       pageoff = offset_in_page(seg1->mr_offset);
-       seg1->mr_offset -= pageoff;     /* start of page */
-       seg1->mr_len += pageoff;
-       len = -pageoff;
        if (nsegs > ia->ri_max_frmr_depth)
                nsegs = ia->ri_max_frmr_depth;
 
-       for (page_no = i = 0; i < nsegs;) {
-               rpcrdma_map_one(device, seg, direction);
-               pa = seg->mr_dma;
-               for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
-                       frmr->fr_pgl->page_list[page_no++] = pa;
-                       pa += PAGE_SIZE;
-               }
-               len += seg->mr_len;
+       for (i = 0; i < nsegs;) {
+               if (seg->mr_page)
+                       sg_set_page(&frmr->sg[i],
+                                   seg->mr_page,
+                                   seg->mr_len,
+                                   offset_in_page(seg->mr_offset));
+               else
+                       sg_set_buf(&frmr->sg[i], seg->mr_offset,
+                                  seg->mr_len);
+
                ++seg;
                ++i;
+
                /* Check for holes */
                if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
                    offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
                        break;
        }
-       dprintk("RPC:       %s: Using frmr %p to map %d segments (%d bytes)\n",
-               __func__, mw, i, len);
-
-       memset(&fastreg_wr, 0, sizeof(fastreg_wr));
-       fastreg_wr.wr_id = (unsigned long)(void *)mw;
-       fastreg_wr.opcode = IB_WR_FAST_REG_MR;
-       fastreg_wr.wr.fast_reg.iova_start = seg1->mr_dma + pageoff;
-       fastreg_wr.wr.fast_reg.page_list = frmr->fr_pgl;
-       fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       fastreg_wr.wr.fast_reg.page_list_len = page_no;
-       fastreg_wr.wr.fast_reg.length = len;
-       fastreg_wr.wr.fast_reg.access_flags = writing ?
-                               IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
-                               IB_ACCESS_REMOTE_READ;
-       mr = frmr->fr_mr;
+       frmr->sg_nents = i;
+
+       dma_nents = ib_dma_map_sg(device, frmr->sg, frmr->sg_nents, direction);
+       if (!dma_nents) {
+               pr_err("RPC:       %s: failed to dma map sg %p sg_nents %u\n",
+                      __func__, frmr->sg, frmr->sg_nents);
+               return -ENOMEM;
+       }
+
+       n = ib_map_mr_sg(mr, frmr->sg, frmr->sg_nents, PAGE_SIZE);
+       if (unlikely(n != frmr->sg_nents)) {
+               pr_err("RPC:       %s: failed to map mr %p (%u/%u)\n",
+                      __func__, frmr->fr_mr, n, frmr->sg_nents);
+               rc = n < 0 ? n : -EINVAL;
+               goto out_senderr;
+       }
+
+       dprintk("RPC:       %s: Using frmr %p to map %u segments (%u bytes)\n",
+               __func__, mw, frmr->sg_nents, mr->length);
+
        key = (u8)(mr->rkey & 0x000000FF);
        ib_update_fast_reg_key(mr, ++key);
-       fastreg_wr.wr.fast_reg.rkey = mr->rkey;
+
+       reg_wr.wr.next = NULL;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = (uintptr_t)mw;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.wr.send_flags = 0;
+       reg_wr.mr = mr;
+       reg_wr.key = mr->rkey;
+       reg_wr.access = writing ?
+                       IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
+                       IB_ACCESS_REMOTE_READ;
 
        DECR_CQCOUNT(&r_xprt->rx_ep);
-       rc = ib_post_send(ia->ri_id->qp, &fastreg_wr, &bad_wr);
+       rc = ib_post_send(ia->ri_id->qp, &reg_wr.wr, &bad_wr);
        if (rc)
                goto out_senderr;
 
+       seg1->mr_dir = direction;
        seg1->rl_mw = mw;
        seg1->mr_rkey = mr->rkey;
-       seg1->mr_base = seg1->mr_dma + pageoff;
-       seg1->mr_nsegs = i;
-       seg1->mr_len = len;
-       return i;
+       seg1->mr_base = mr->iova;
+       seg1->mr_nsegs = frmr->sg_nents;
+       seg1->mr_len = mr->length;
+
+       return frmr->sg_nents;
 
 out_senderr:
        dprintk("RPC:       %s: ib_post_send status %i\n", __func__, rc);
-       while (i--)
-               rpcrdma_unmap_one(device, --seg);
+       ib_dma_unmap_sg(device, frmr->sg, dma_nents, direction);
        __frwr_queue_recovery(mw);
        return rc;
 }
@@ -402,22 +419,22 @@ frwr_op_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
        struct rpcrdma_mr_seg *seg1 = seg;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        struct rpcrdma_mw *mw = seg1->rl_mw;
+       struct rpcrdma_frmr *frmr = &mw->r.frmr;
        struct ib_send_wr invalidate_wr, *bad_wr;
        int rc, nsegs = seg->mr_nsegs;
 
        dprintk("RPC:       %s: FRMR %p\n", __func__, mw);
 
        seg1->rl_mw = NULL;
-       mw->r.frmr.fr_state = FRMR_IS_INVALID;
+       frmr->fr_state = FRMR_IS_INVALID;
 
        memset(&invalidate_wr, 0, sizeof(invalidate_wr));
        invalidate_wr.wr_id = (unsigned long)(void *)mw;
        invalidate_wr.opcode = IB_WR_LOCAL_INV;
-       invalidate_wr.ex.invalidate_rkey = mw->r.frmr.fr_mr->rkey;
+       invalidate_wr.ex.invalidate_rkey = frmr->fr_mr->rkey;
        DECR_CQCOUNT(&r_xprt->rx_ep);
 
-       while (seg1->mr_nsegs--)
-               rpcrdma_unmap_one(ia->ri_device, seg++);
+       ib_dma_unmap_sg(ia->ri_device, frmr->sg, frmr->sg_nents, seg1->mr_dir);
        read_lock(&ia->ri_qplock);
        rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
        read_unlock(&ia->ri_qplock);
index f0c3ff67ca987427136baebf67034ad3bf58a27f..ff4f01e527ecc08a1480ecba8f00d41a90a76571 100644 (file)
@@ -126,7 +126,7 @@ int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt,
                        u64 rs_offset,
                        bool last)
 {
-       struct ib_send_wr read_wr;
+       struct ib_rdma_wr read_wr;
        int pages_needed = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
        struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
        int ret, read, pno;
@@ -180,16 +180,16 @@ int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt,
                clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
 
        memset(&read_wr, 0, sizeof(read_wr));
-       read_wr.wr_id = (unsigned long)ctxt;
-       read_wr.opcode = IB_WR_RDMA_READ;
-       ctxt->wr_op = read_wr.opcode;
-       read_wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.wr.rdma.rkey = rs_handle;
-       read_wr.wr.rdma.remote_addr = rs_offset;
-       read_wr.sg_list = ctxt->sge;
-       read_wr.num_sge = pages_needed;
-
-       ret = svc_rdma_send(xprt, &read_wr);
+       read_wr.wr.wr_id = (unsigned long)ctxt;
+       read_wr.wr.opcode = IB_WR_RDMA_READ;
+       ctxt->wr_op = read_wr.wr.opcode;
+       read_wr.wr.send_flags = IB_SEND_SIGNALED;
+       read_wr.rkey = rs_handle;
+       read_wr.remote_addr = rs_offset;
+       read_wr.wr.sg_list = ctxt->sge;
+       read_wr.wr.num_sge = pages_needed;
+
+       ret = svc_rdma_send(xprt, &read_wr.wr);
        if (ret) {
                pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
                set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -219,14 +219,14 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
                         u64 rs_offset,
                         bool last)
 {
-       struct ib_send_wr read_wr;
+       struct ib_rdma_wr read_wr;
        struct ib_send_wr inv_wr;
-       struct ib_send_wr fastreg_wr;
+       struct ib_reg_wr reg_wr;
        u8 key;
-       int pages_needed = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
+       int nents = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
        struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
        struct svc_rdma_fastreg_mr *frmr = svc_rdma_get_frmr(xprt);
-       int ret, read, pno;
+       int ret, read, pno, dma_nents, n;
        u32 pg_off = *page_offset;
        u32 pg_no = *page_no;
 
@@ -235,17 +235,14 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
 
        ctxt->direction = DMA_FROM_DEVICE;
        ctxt->frmr = frmr;
-       pages_needed = min_t(int, pages_needed, xprt->sc_frmr_pg_list_len);
-       read = min_t(int, (pages_needed << PAGE_SHIFT) - *page_offset,
-                    rs_length);
+       nents = min_t(unsigned int, nents, xprt->sc_frmr_pg_list_len);
+       read = min_t(int, (nents << PAGE_SHIFT) - *page_offset, rs_length);
 
-       frmr->kva = page_address(rqstp->rq_arg.pages[pg_no]);
        frmr->direction = DMA_FROM_DEVICE;
        frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
-       frmr->map_len = pages_needed << PAGE_SHIFT;
-       frmr->page_list_len = pages_needed;
+       frmr->sg_nents = nents;
 
-       for (pno = 0; pno < pages_needed; pno++) {
+       for (pno = 0; pno < nents; pno++) {
                int len = min_t(int, rs_length, PAGE_SIZE - pg_off);
 
                head->arg.pages[pg_no] = rqstp->rq_arg.pages[pg_no];
@@ -253,17 +250,12 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
                head->arg.len += len;
                if (!pg_off)
                        head->count++;
+
+               sg_set_page(&frmr->sg[pno], rqstp->rq_arg.pages[pg_no],
+                           len, pg_off);
+
                rqstp->rq_respages = &rqstp->rq_arg.pages[pg_no+1];
                rqstp->rq_next_page = rqstp->rq_respages + 1;
-               frmr->page_list->page_list[pno] =
-                       ib_dma_map_page(xprt->sc_cm_id->device,
-                                       head->arg.pages[pg_no], 0,
-                                       PAGE_SIZE, DMA_FROM_DEVICE);
-               ret = ib_dma_mapping_error(xprt->sc_cm_id->device,
-                                          frmr->page_list->page_list[pno]);
-               if (ret)
-                       goto err;
-               atomic_inc(&xprt->sc_dma_used);
 
                /* adjust offset and wrap to next page if needed */
                pg_off += len;
@@ -279,43 +271,57 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
        else
                clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
 
+       dma_nents = ib_dma_map_sg(xprt->sc_cm_id->device,
+                                 frmr->sg, frmr->sg_nents,
+                                 frmr->direction);
+       if (!dma_nents) {
+               pr_err("svcrdma: failed to dma map sg %p\n",
+                      frmr->sg);
+               return -ENOMEM;
+       }
+       atomic_inc(&xprt->sc_dma_used);
+
+       n = ib_map_mr_sg(frmr->mr, frmr->sg, frmr->sg_nents, PAGE_SIZE);
+       if (unlikely(n != frmr->sg_nents)) {
+               pr_err("svcrdma: failed to map mr %p (%d/%d elements)\n",
+                      frmr->mr, n, frmr->sg_nents);
+               return n < 0 ? n : -EINVAL;
+       }
+
        /* Bump the key */
        key = (u8)(frmr->mr->lkey & 0x000000FF);
        ib_update_fast_reg_key(frmr->mr, ++key);
 
-       ctxt->sge[0].addr = (unsigned long)frmr->kva + *page_offset;
+       ctxt->sge[0].addr = frmr->mr->iova;
        ctxt->sge[0].lkey = frmr->mr->lkey;
-       ctxt->sge[0].length = read;
+       ctxt->sge[0].length = frmr->mr->length;
        ctxt->count = 1;
        ctxt->read_hdr = head;
 
-       /* Prepare FASTREG WR */
-       memset(&fastreg_wr, 0, sizeof(fastreg_wr));
-       fastreg_wr.opcode = IB_WR_FAST_REG_MR;
-       fastreg_wr.send_flags = IB_SEND_SIGNALED;
-       fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
-       fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
-       fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
-       fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       fastreg_wr.wr.fast_reg.length = frmr->map_len;
-       fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
-       fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
-       fastreg_wr.next = &read_wr;
+       /* Prepare REG WR */
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = 0;
+       reg_wr.wr.send_flags = IB_SEND_SIGNALED;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = frmr->mr;
+       reg_wr.key = frmr->mr->lkey;
+       reg_wr.access = frmr->access_flags;
+       reg_wr.wr.next = &read_wr.wr;
 
        /* Prepare RDMA_READ */
        memset(&read_wr, 0, sizeof(read_wr));
-       read_wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.wr.rdma.rkey = rs_handle;
-       read_wr.wr.rdma.remote_addr = rs_offset;
-       read_wr.sg_list = ctxt->sge;
-       read_wr.num_sge = 1;
+       read_wr.wr.send_flags = IB_SEND_SIGNALED;
+       read_wr.rkey = rs_handle;
+       read_wr.remote_addr = rs_offset;
+       read_wr.wr.sg_list = ctxt->sge;
+       read_wr.wr.num_sge = 1;
        if (xprt->sc_dev_caps & SVCRDMA_DEVCAP_READ_W_INV) {
-               read_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
-               read_wr.wr_id = (unsigned long)ctxt;
-               read_wr.ex.invalidate_rkey = ctxt->frmr->mr->lkey;
+               read_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
+               read_wr.wr.wr_id = (unsigned long)ctxt;
+               read_wr.wr.ex.invalidate_rkey = ctxt->frmr->mr->lkey;
        } else {
-               read_wr.opcode = IB_WR_RDMA_READ;
-               read_wr.next = &inv_wr;
+               read_wr.wr.opcode = IB_WR_RDMA_READ;
+               read_wr.wr.next = &inv_wr;
                /* Prepare invalidate */
                memset(&inv_wr, 0, sizeof(inv_wr));
                inv_wr.wr_id = (unsigned long)ctxt;
@@ -323,10 +329,10 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
                inv_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_FENCE;
                inv_wr.ex.invalidate_rkey = frmr->mr->lkey;
        }
-       ctxt->wr_op = read_wr.opcode;
+       ctxt->wr_op = read_wr.wr.opcode;
 
        /* Post the chain */
-       ret = svc_rdma_send(xprt, &fastreg_wr);
+       ret = svc_rdma_send(xprt, &reg_wr.wr);
        if (ret) {
                pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
                set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -340,7 +346,8 @@ int rdma_read_chunk_frmr(struct svcxprt_rdma *xprt,
        atomic_inc(&rdma_stat_read);
        return ret;
  err:
-       svc_rdma_unmap_dma(ctxt);
+       ib_dma_unmap_sg(xprt->sc_cm_id->device,
+                       frmr->sg, frmr->sg_nents, frmr->direction);
        svc_rdma_put_context(ctxt, 0);
        svc_rdma_put_frmr(xprt, frmr);
        return ret;
index 1dfae83170650ec26d53973e6627acdaa78dcddf..969a1ab75fc3c5fb8011157e4f57e8d08f560b42 100644 (file)
@@ -217,7 +217,7 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
                      u32 xdr_off, int write_len,
                      struct svc_rdma_req_map *vec)
 {
-       struct ib_send_wr write_wr;
+       struct ib_rdma_wr write_wr;
        struct ib_sge *sge;
        int xdr_sge_no;
        int sge_no;
@@ -282,17 +282,17 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
        /* Prepare WRITE WR */
        memset(&write_wr, 0, sizeof write_wr);
        ctxt->wr_op = IB_WR_RDMA_WRITE;
-       write_wr.wr_id = (unsigned long)ctxt;
-       write_wr.sg_list = &sge[0];
-       write_wr.num_sge = sge_no;
-       write_wr.opcode = IB_WR_RDMA_WRITE;
-       write_wr.send_flags = IB_SEND_SIGNALED;
-       write_wr.wr.rdma.rkey = rmr;
-       write_wr.wr.rdma.remote_addr = to;
+       write_wr.wr.wr_id = (unsigned long)ctxt;
+       write_wr.wr.sg_list = &sge[0];
+       write_wr.wr.num_sge = sge_no;
+       write_wr.wr.opcode = IB_WR_RDMA_WRITE;
+       write_wr.wr.send_flags = IB_SEND_SIGNALED;
+       write_wr.rkey = rmr;
+       write_wr.remote_addr = to;
 
        /* Post It */
        atomic_inc(&rdma_stat_write);
-       if (svc_rdma_send(xprt, &write_wr))
+       if (svc_rdma_send(xprt, &write_wr.wr))
                goto err;
        return write_len - bc;
  err:
index fcc3eb80c265456d88bfe733ac9d6c1301d24e92..a266e870d870e8b2cf0d938c3009460b46fddc7b 100644 (file)
@@ -692,8 +692,8 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
        if (!cma_xprt)
                return ERR_PTR(-ENOMEM);
 
-       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP,
-                                  IB_QPT_RC);
+       listen_id = rdma_create_id(&init_net, rdma_listen_handler, cma_xprt,
+                                  RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(listen_id)) {
                ret = PTR_ERR(listen_id);
                dprintk("svcrdma: rdma_create_id failed = %d\n", ret);
@@ -732,7 +732,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
 static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
 {
        struct ib_mr *mr;
-       struct ib_fast_reg_page_list *pl;
+       struct scatterlist *sg;
        struct svc_rdma_fastreg_mr *frmr;
        u32 num_sg;
 
@@ -745,13 +745,14 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
        if (IS_ERR(mr))
                goto err_free_frmr;
 
-       pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
-                                        num_sg);
-       if (IS_ERR(pl))
+       sg = kcalloc(RPCSVC_MAXPAGES, sizeof(*sg), GFP_KERNEL);
+       if (!sg)
                goto err_free_mr;
 
+       sg_init_table(sg, RPCSVC_MAXPAGES);
+
        frmr->mr = mr;
-       frmr->page_list = pl;
+       frmr->sg = sg;
        INIT_LIST_HEAD(&frmr->frmr_list);
        return frmr;
 
@@ -771,8 +772,8 @@ static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
                frmr = list_entry(xprt->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
+               kfree(frmr->sg);
                ib_dereg_mr(frmr->mr);
-               ib_free_fast_reg_page_list(frmr->page_list);
                kfree(frmr);
        }
 }
@@ -786,8 +787,7 @@ struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
                frmr = list_entry(rdma->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
-               frmr->map_len = 0;
-               frmr->page_list_len = 0;
+               frmr->sg_nents = 0;
        }
        spin_unlock_bh(&rdma->sc_frmr_q_lock);
        if (frmr)
@@ -796,25 +796,13 @@ struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
        return rdma_alloc_frmr(rdma);
 }
 
-static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
-                          struct svc_rdma_fastreg_mr *frmr)
-{
-       int page_no;
-       for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
-               dma_addr_t addr = frmr->page_list->page_list[page_no];
-               if (ib_dma_mapping_error(frmr->mr->device, addr))
-                       continue;
-               atomic_dec(&xprt->sc_dma_used);
-               ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
-                                 frmr->direction);
-       }
-}
-
 void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
                       struct svc_rdma_fastreg_mr *frmr)
 {
        if (frmr) {
-               frmr_unmap_dma(rdma, frmr);
+               ib_dma_unmap_sg(rdma->sc_cm_id->device,
+                               frmr->sg, frmr->sg_nents, frmr->direction);
+               atomic_dec(&rdma->sc_dma_used);
                spin_lock_bh(&rdma->sc_frmr_q_lock);
                WARN_ON_ONCE(!list_empty(&frmr->frmr_list));
                list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
index 5502d4dade74aa8646f89305b011d215294352e0..f63369bd01c54b9d7df2a15511c1fa066289a91f 100644 (file)
@@ -432,7 +432,8 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
 
        init_completion(&ia->ri_done);
 
-       id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
+       id = rdma_create_id(&init_net, rpcrdma_conn_upcall, xprt, RDMA_PS_TCP,
+                           IB_QPT_RC);
        if (IS_ERR(id)) {
                rc = PTR_ERR(id);
                dprintk("RPC:       %s: rdma_create_id() failed %i\n",
index c09414e6f91b0428bd7cc5fd6f2b1c67f8830b23..c82abf44e39db9954cd7e27fab2595b9552c9668 100644 (file)
@@ -193,7 +193,8 @@ enum rpcrdma_frmr_state {
 };
 
 struct rpcrdma_frmr {
-       struct ib_fast_reg_page_list    *fr_pgl;
+       struct scatterlist              *sg;
+       int                             sg_nents;
        struct ib_mr                    *fr_mr;
        enum rpcrdma_frmr_state         fr_state;
        struct work_struct              fr_work;
index 125d6402f64f8555ec85b42f4c39e3af0f46ef3b..d6b75bb495b35ad503eb815867df697db3cd914f 100644 (file)
@@ -4,14 +4,14 @@
  *
  * The define_trace.h below will also look for a file name of
  * TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
- * In this case, it would look for sample.h
+ * In this case, it would look for sample-trace.h
  *
  * If the header name will be different than the system name
  * (as in this case), then you can override the header name that
  * define_trace.h will look up by defining TRACE_INCLUDE_FILE
  *
  * This file is called trace-events-sample.h but we want the system
- * to be called "sample". Therefore we must define the name of this
+ * to be called "sample-trace". Therefore we must define the name of this
  * file:
  *
  * #define TRACE_INCLUDE_FILE trace-events-sample
  *
  *         memcpy(__entry->foo, bar, 10);
  *
- *   __dynamic_array: This is similar to array, but can vary is size from
+ *   __dynamic_array: This is similar to array, but can vary its size from
  *         instance to instance of the tracepoint being called.
  *         Like __array, this too has three elements (type, name, size);
  *         type is the type of the element, name is the name of the array.
index 5a6edacc85d9c2517f837bf23c670709250935ea..840b97328b399188edce45dc3a456917f2bf99d7 100644 (file)
@@ -197,5 +197,10 @@ int main(void)
        DEVID_FIELD(ulpi_device_id, vendor);
        DEVID_FIELD(ulpi_device_id, product);
 
+       DEVID(hda_device_id);
+       DEVID_FIELD(hda_device_id, vendor_id);
+       DEVID_FIELD(hda_device_id, rev_id);
+       DEVID_FIELD(hda_device_id, api_version);
+
        return 0;
 }
index 9bc2cfe0ee3709036669acf63531f8abec7fa4cf..5b96206e9aab833f9a666bc7cf52d57662929b3d 100644 (file)
@@ -1254,6 +1254,23 @@ static int do_ulpi_entry(const char *filename, void *symval,
 }
 ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry);
 
+/* Looks like: hdaudio:vNrNaN */
+static int do_hda_entry(const char *filename, void *symval, char *alias)
+{
+       DEF_FIELD(symval, hda_device_id, vendor_id);
+       DEF_FIELD(symval, hda_device_id, rev_id);
+       DEF_FIELD(symval, hda_device_id, api_version);
+
+       strcpy(alias, "hdaudio:");
+       ADD(alias, "v", vendor_id != 0, vendor_id);
+       ADD(alias, "r", rev_id != 0, rev_id);
+       ADD(alias, "a", api_version != 0, api_version);
+
+       add_wildcard(alias);
+       return 1;
+}
+ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index 3d1984e59a3016f29ecf84a97305ca8d9647b5ed..698768bdc5815021b61814ddabc408d4310c3c0e 100644 (file)
@@ -42,6 +42,7 @@
 
 #ifndef EM_AARCH64
 #define EM_AARCH64     183
+#define R_AARCH64_NONE         0
 #define R_AARCH64_ABS64        257
 #endif
 
@@ -160,6 +161,22 @@ static int make_nop_x86(void *map, size_t const offset)
        return 0;
 }
 
+static unsigned char ideal_nop4_arm64[4] = {0x1f, 0x20, 0x03, 0xd5};
+static int make_nop_arm64(void *map, size_t const offset)
+{
+       uint32_t *ptr;
+
+       ptr = map + offset;
+       /* bl <_mcount> is 0x94000000 before relocation */
+       if (*ptr != 0x94000000)
+               return -1;
+
+       /* Convert to nop */
+       ulseek(fd_map, offset, SEEK_SET);
+       uwrite(fd_map, ideal_nop, 4);
+       return 0;
+}
+
 /*
  * Get the whole file as a programming convenience in order to avoid
  * malloc+lseek+read+free of many pieces.  If successful, then mmap
@@ -345,6 +362,7 @@ do_file(char const *const fname)
                break;
        case EM_386:
                reltype = R_386_32;
+               rel_type_nop = R_386_NONE;
                make_nop = make_nop_x86;
                ideal_nop = ideal_nop5_x86_32;
                mcount_adjust_32 = -1;
@@ -353,7 +371,12 @@ do_file(char const *const fname)
                         altmcount = "__gnu_mcount_nc";
                         break;
        case EM_AARCH64:
-                        reltype = R_AARCH64_ABS64; gpfx = '_'; break;
+                       reltype = R_AARCH64_ABS64;
+                       make_nop = make_nop_arm64;
+                       rel_type_nop = R_AARCH64_NONE;
+                       ideal_nop = ideal_nop4_arm64;
+                       gpfx = '_';
+                       break;
        case EM_IA_64:   reltype = R_IA64_IMM64;   gpfx = '_'; break;
        case EM_METAG:   reltype = R_METAG_ADDR32;
                         altmcount = "_mcount_wrapper";
@@ -371,6 +394,7 @@ do_file(char const *const fname)
                make_nop = make_nop_x86;
                ideal_nop = ideal_nop5_x86_64;
                reltype = R_X86_64_64;
+               rel_type_nop = R_X86_64_NONE;
                mcount_adjust_64 = -1;
                break;
        }  /* end switch */
index 49b582a225b0bc320f4447a9c53c11330bb062af..b9897e2be404d24735068f584831c51ef90efccd 100644 (file)
@@ -377,7 +377,7 @@ static void nop_mcount(Elf_Shdr const *const relhdr,
 
                if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
                        if (make_nop)
-                               ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset);
+                               ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
                        if (warn_on_notrace_sect && !once) {
                                printf("Section %s has mcount callers being ignored\n",
                                       txtname);
index 38590b322c544bbec8a2c6f2852eced1b8986dfb..fbd5dad0c484006c1881156e2930d5020d589672 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,7 +44,11 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_reset,
 };
 
-static unsigned long pxa2xx_ac97_pcm_out_req = 12;
+static struct pxad_param pxa2xx_ac97_pcm_out_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 12,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -51,7 +56,11 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
        .filter_data    = &pxa2xx_ac97_pcm_out_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_in_req = 11;
+static struct pxad_param pxa2xx_ac97_pcm_in_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 11,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
index 01f8fdc42b1b8a3e2c5a83c955bae76f23256071..e9b98af6b52c83faecccd4cc1011286a75560849 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -15,8 +16,6 @@
 #include <sound/pxa2xx-lib.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <mach/dma.h>
-
 #include "pxa2xx-pcm.h"
 
 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
@@ -31,7 +30,7 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192 - 32,
        .periods_min            = 1,
-       .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
+       .periods_max            = 256,
        .buffer_bytes_max       = 128 * 1024,
        .fifo_size              = 32,
 };
@@ -39,65 +38,29 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
 int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-       size_t totsize = params_buffer_bytes(params);
-       size_t period = params_period_bytes(params);
-       pxa_dma_desc *dma_desc;
-       dma_addr_t dma_buff_phys, next_desc_phys;
-       u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+       struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_dmaengine_dai_dma_data *dma_params;
+       struct dma_slave_config config;
+       int ret;
 
-       /* temporary transition hack */
-       switch (rtd->params->addr_width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-               dcmd |= DCMD_WIDTH1;
-               break;
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-               dcmd |= DCMD_WIDTH2;
-               break;
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-               dcmd |= DCMD_WIDTH4;
-               break;
-       default:
-               /* can't happen */
-               break;
-       }
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       if (!dma_params)
+               return 0;
 
-       switch (rtd->params->maxburst) {
-       case 8:
-               dcmd |= DCMD_BURST8;
-               break;
-       case 16:
-               dcmd |= DCMD_BURST16;
-               break;
-       case 32:
-               dcmd |= DCMD_BURST32;
-               break;
-       }
+       ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
+       if (ret)
+               return ret;
 
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = totsize;
+       snd_dmaengine_pcm_set_config_from_dai_data(substream,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+                       &config);
 
-       dma_desc = rtd->dma_desc_array;
-       next_desc_phys = rtd->dma_desc_array_phys;
-       dma_buff_phys = runtime->dma_addr;
-       do {
-               next_desc_phys += sizeof(pxa_dma_desc);
-               dma_desc->ddadr = next_desc_phys;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       dma_desc->dsadr = dma_buff_phys;
-                       dma_desc->dtadr = rtd->params->addr;
-               } else {
-                       dma_desc->dsadr = rtd->params->addr;
-                       dma_desc->dtadr = dma_buff_phys;
-               }
-               if (period > totsize)
-                       period = totsize;
-               dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
-               dma_desc++;
-               dma_buff_phys += period;
-       } while (totsize -= period);
-       dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+       ret = dmaengine_slave_config(chan, &config);
+       if (ret)
+               return ret;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
        return 0;
 }
@@ -105,13 +68,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
 
 int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
-
-       if (rtd && rtd->params && rtd->params->filter_data) {
-               unsigned long req = *(unsigned long *) rtd->params->filter_data;
-               DRCMR(req) = 0;
-       }
-
        snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
 }
@@ -119,100 +75,36 @@ EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
 
 int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) = DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-               break;
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
-               DCSR(prtd->dma_ch) |= DCSR_RUN;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
+       return snd_dmaengine_pcm_trigger(substream, cmd);
 }
 EXPORT_SYMBOL(pxa2xx_pcm_trigger);
 
 snd_pcm_uframes_t
 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd = runtime->private_data;
-
-       dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                        DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
-       snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-
-       if (x == runtime->buffer_size)
-               x = 0;
-       return x;
+       return snd_dmaengine_pcm_pointer(substream);
 }
 EXPORT_SYMBOL(pxa2xx_pcm_pointer);
 
 int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-       unsigned long req;
-
-       if (!prtd || !prtd->params)
-               return 0;
-
-       if (prtd->dma_ch == -1)
-               return -EINVAL;
-
-       DCSR(prtd->dma_ch) &= ~DCSR_RUN;
-       DCSR(prtd->dma_ch) = 0;
-       DCMD(prtd->dma_ch) = 0;
-       req = *(unsigned long *) prtd->params->filter_data;
-       DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
-
        return 0;
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
 
-void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       int dcsr;
-
-       dcsr = DCSR(dma_ch);
-       DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
-
-       if (dcsr & DCSR_ENDINTR) {
-               snd_pcm_period_elapsed(substream);
-       } else {
-               printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
-                       dma_ch, dcsr);
-               snd_pcm_stop_xrun(substream);
-       }
-}
-EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
-
 int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd;
+       struct snd_dmaengine_dai_dma_data *dma_params;
        int ret;
 
        runtime->hw = pxa2xx_pcm_hardware;
 
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       if (!dma_params)
+               return 0;
+
        /*
         * For mysterious reasons (and despite what the manual says)
         * playback samples are lost if the DMA count is not a multiple
@@ -221,48 +113,27 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
        ret = snd_pcm_hw_constraint_step(runtime, 0,
                SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
        if (ret)
-               goto out;
+               return ret;
 
        ret = snd_pcm_hw_constraint_step(runtime, 0,
                SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
        if (ret)
-               goto out;
+               return ret;
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0)
-               goto out;
-
-       ret = -ENOMEM;
-       rtd = kzalloc(sizeof(*rtd), GFP_KERNEL);
-       if (!rtd)
-               goto out;
-       rtd->dma_desc_array =
-               dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                                      &rtd->dma_desc_array_phys, GFP_KERNEL);
-       if (!rtd->dma_desc_array)
-               goto err1;
+               return ret;
 
-       rtd->dma_ch = -1;
-       runtime->private_data = rtd;
-       return 0;
-
- err1:
-       kfree(rtd);
- out:
-       return ret;
+       return snd_dmaengine_pcm_open_request_chan(substream,
+                                       pxad_filter_fn,
+                                       dma_params->filter_data);
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_open);
 
 int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *rtd = runtime->private_data;
-
-       dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
-                             rtd->dma_desc_array, rtd->dma_desc_array_phys);
-       kfree(rtd);
-       return 0;
+       return snd_dmaengine_pcm_close_release_chan(substream);
 }
 EXPORT_SYMBOL(__pxa2xx_pcm_close);
 
index 83be8e3f095ef46fb58d7567c84c5cb1b0db1b73..83fcfac977396cd1d365289d70ca0857bb3127c4 100644 (file)
@@ -46,17 +46,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 
        rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                      client->playback_params : client->capture_params;
-       ret = pxa_request_dma("dma", DMA_PRIO_LOW,
-                             pxa2xx_pcm_dma_irq, substream);
-       if (ret < 0)
-               goto err2;
-       rtd->dma_ch = ret;
 
        ret = client->startup(substream);
        if (!ret)
-               goto out;
+               goto err2;
+
+       return 0;
 
-       pxa_free_dma(rtd->dma_ch);
  err2:
        __pxa2xx_pcm_close(substream);
  out:
@@ -66,9 +62,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_pcm_client *client = substream->private_data;
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-       pxa_free_dma(rtd->dma_ch);
        client->shutdown(substream);
 
        return __pxa2xx_pcm_close(substream);
index 00330985beec1f7ac0e07adb076904f98a35d51a..8fa2b7c9e6b881a5576b373d060f3766277d33e3 100644 (file)
@@ -13,8 +13,6 @@
 struct pxa2xx_runtime_data {
        int dma_ch;
        struct snd_dmaengine_dai_dma_data *params;
-       struct pxa_dma_desc *dma_desc_array;
-       dma_addr_t dma_desc_array_phys;
 };
 
 struct pxa2xx_pcm_client {
index 6c96feeaf01eb08794be6321fa0ac35aba66b3e8..e3e949126a5639c6a4a623750ec35922704c5110 100644 (file)
@@ -4,7 +4,7 @@ config SND_TIMER
 
 config SND_PCM
        tristate
-       select SND_TIMER
+       select SND_TIMER if SND_PCM_TIMER
 
 config SND_PCM_ELD
        bool
@@ -93,6 +93,17 @@ config SND_PCM_OSS_PLUGINS
           support conversion of channels, formats and rates. It will
           behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
 
+config SND_PCM_TIMER
+       bool "PCM timer interface" if EXPERT
+       default y
+       help
+         If you disable this option, pcm timer will be inavailable, so
+         those stubs used pcm timer (e.g. dmix, dsnoop & co) may work
+         incorrectlly.
+
+         For some embedded device, we may disable it to reduce memory
+         footprint, about 20KB on x86_64 platform.
+
 config SND_SEQUENCER_OSS
        bool "OSS Sequencer API"
        depends on SND_SEQUENCER
index 3354f91e003ad13e100887c9bf9050c5ae51252a..48ab4b8f82790809838c3a87535587636ea69ed7 100644 (file)
@@ -13,8 +13,9 @@ snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
 snd-$(CONFIG_SND_VMASTER) += vmaster.o
 snd-$(CONFIG_SND_JACK)   += ctljack.o jack.o
 
-snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
+snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_misc.o \
                pcm_memory.o memalloc.o
+snd-pcm-$(CONFIG_SND_PCM_TIMER) += pcm_timer.o
 snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
 snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o
 snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
index a99f7200ff3f2929dd17bc85a64c296460346e02..7a8c79dd9734039d2e14ae1a7f23763e7d6fc519 100644 (file)
@@ -1177,7 +1177,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
        struct snd_mixer_oss *mixer = entry->private_data;
        char line[128], str[32], idxstr[16];
        const char *cptr;
-       int ch, idx;
+       unsigned int idx;
+       int ch;
        struct snd_mixer_oss_assign_table *tbl;
        struct slot *slot;
 
index 02bd96954dc42c05266ef9d04a3d77918cf9cf6c..308c9ecf73db18415aa1157ee4e895731a5abc36 100644 (file)
@@ -1014,9 +1014,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        snd_free_pages((void*)runtime->control,
                       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
        kfree(runtime->hw_constraints.rules);
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       kfree(runtime->hwptr_log);
-#endif
        kfree(runtime);
        substream->runtime = NULL;
        put_pid(substream->pid);
index 7d45645f10ba99e33b54b3218559778db3aca36a..6b5a811e01a544f3379829b8ebfa3773904691bb 100644 (file)
@@ -801,7 +801,7 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
  * negative error code.
  */
 int snd_interval_ratnum(struct snd_interval *i,
-                       unsigned int rats_count, struct snd_ratnum *rats,
+                       unsigned int rats_count, const struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp)
 {
        unsigned int best_num, best_den;
@@ -920,7 +920,8 @@ EXPORT_SYMBOL(snd_interval_ratnum);
  * negative error code.
  */
 static int snd_interval_ratden(struct snd_interval *i,
-                              unsigned int rats_count, struct snd_ratden *rats,
+                              unsigned int rats_count,
+                              const struct snd_ratden *rats,
                               unsigned int *nump, unsigned int *denp)
 {
        unsigned int best_num, best_diff, best_den;
@@ -1339,7 +1340,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hw_constraint_ratnums *r = rule->private;
+       const struct snd_pcm_hw_constraint_ratnums *r = rule->private;
        unsigned int num = 0, den = 0;
        int err;
        err = snd_interval_ratnum(hw_param_interval(params, rule->var),
@@ -1363,10 +1364,10 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratnums *r)
+                                 const struct snd_pcm_hw_constraint_ratnums *r)
 {
        return snd_pcm_hw_rule_add(runtime, cond, var,
-                                  snd_pcm_hw_rule_ratnums, r,
+                                  snd_pcm_hw_rule_ratnums, (void *)r,
                                   var, -1);
 }
 
@@ -1375,7 +1376,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
 static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hw_constraint_ratdens *r = rule->private;
+       const struct snd_pcm_hw_constraint_ratdens *r = rule->private;
        unsigned int num = 0, den = 0;
        int err = snd_interval_ratden(hw_param_interval(params, rule->var),
                                  r->nrats, r->rats, &num, &den);
@@ -1398,10 +1399,10 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
 int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
-                                 struct snd_pcm_hw_constraint_ratdens *r)
+                                 const struct snd_pcm_hw_constraint_ratdens *r)
 {
        return snd_pcm_hw_rule_add(runtime, cond, var,
-                                  snd_pcm_hw_rule_ratdens, r,
+                                  snd_pcm_hw_rule_ratdens, (void *)r,
                                   var, -1);
 }
 
@@ -1875,20 +1876,17 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
                return;
        runtime = substream->runtime;
 
-       if (runtime->transfer_ack_begin)
-               runtime->transfer_ack_begin(substream);
-
        snd_pcm_stream_lock_irqsave(substream, flags);
        if (!snd_pcm_running(substream) ||
            snd_pcm_update_hw_ptr0(substream, 1) < 0)
                goto _end;
 
+#ifdef CONFIG_SND_PCM_TIMER
        if (substream->timer_running)
                snd_timer_interrupt(substream->timer, 1);
+#endif
  _end:
        snd_pcm_stream_unlock_irqrestore(substream, flags);
-       if (runtime->transfer_ack_end)
-               runtime->transfer_ack_end(substream);
        kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
 }
 
index 75888dd38a7fc87acf5fcd7789570ad353dce482..a8b27cdc2844855fb2d030a246bf2374e7e27269 100644 (file)
@@ -486,6 +486,16 @@ static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
        snd_pcm_stream_unlock_irq(substream);
 }
 
+static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
+                                       int event)
+{
+#ifdef CONFIG_SND_PCM_TIMER
+       if (substream->timer)
+               snd_timer_notify(substream->timer, event,
+                                       &substream->runtime->trigger_tstamp);
+#endif
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -650,7 +660,8 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
        }
        snd_pcm_stream_unlock_irq(substream);
 
-       if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
+       if (params->tstamp_mode < 0 ||
+           params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
                return -EINVAL;
        if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
            params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
@@ -1042,9 +1053,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, ULONG_MAX);
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
 }
 
 static struct action_ops snd_pcm_action_start = {
@@ -1092,9 +1101,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
        if (runtime->status->state != state) {
                snd_pcm_trigger_tstamp(substream);
                runtime->status->state = state;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
        }
        wake_up(&runtime->sleep);
        wake_up(&runtime->tsleep);
@@ -1208,18 +1215,12 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
        snd_pcm_trigger_tstamp(substream);
        if (push) {
                runtime->status->state = SNDRV_PCM_STATE_PAUSED;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer,
-                                        SNDRV_TIMER_EVENT_MPAUSE,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE);
                wake_up(&runtime->sleep);
                wake_up(&runtime->tsleep);
        } else {
                runtime->status->state = SNDRV_PCM_STATE_RUNNING;
-               if (substream->timer)
-                       snd_timer_notify(substream->timer,
-                                        SNDRV_TIMER_EVENT_MCONTINUE,
-                                        &runtime->trigger_tstamp);
+               snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE);
        }
 }
 
@@ -1267,9 +1268,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
        snd_pcm_trigger_tstamp(substream);
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND);
        wake_up(&runtime->sleep);
        wake_up(&runtime->tsleep);
 }
@@ -1373,9 +1372,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        runtime->status->state = runtime->status->suspended_state;
-       if (substream->timer)
-               snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
-                                &runtime->trigger_tstamp);
+       snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
 }
 
 static struct action_ops snd_pcm_action_resume = {
@@ -2226,7 +2223,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
 
        snd_pcm_drop(substream);
        if (substream->hw_opened) {
-               if (substream->ops->hw_free != NULL)
+               if (substream->ops->hw_free &&
+                   substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
                        substream->ops->hw_free(substream);
                substream->ops->close(substream);
                substream->hw_opened = 0;
index ccd893566f1decbe80d21d350c7041d97c969988..046cb586fb2f7271c88dc1e02354625d6dcca864 100644 (file)
@@ -91,8 +91,7 @@ snd_seq_oss_readq_clear(struct seq_oss_readq *q)
                q->head = q->tail = 0;
        }
        /* if someone sleeping, wake'em up */
-       if (waitqueue_active(&q->midi_sleep))
-               wake_up(&q->midi_sleep);
+       wake_up(&q->midi_sleep);
        q->input_time = (unsigned long)-1;
 }
 
@@ -138,8 +137,7 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
        q->qlen++;
 
        /* wake up sleeper */
-       if (waitqueue_active(&q->midi_sleep))
-               wake_up(&q->midi_sleep);
+       wake_up(&q->midi_sleep);
 
        spin_unlock_irqrestore(&q->lock, flags);
 
index d50338bbc21f1dbc2637ae9b2938716679b919c9..1f6788a18444111c724bc417741c2a398da89900 100644 (file)
@@ -138,9 +138,7 @@ snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
        spin_lock_irqsave(&q->sync_lock, flags);
        q->sync_time = time;
        q->sync_event_put = 0;
-       if (waitqueue_active(&q->sync_sleep)) {
-               wake_up(&q->sync_sleep);
-       }
+       wake_up(&q->sync_sleep);
        spin_unlock_irqrestore(&q->sync_lock, flags);
 }
 
index 8850b7de1d380585a784e6f72a5dccc5812b5ad4..bee0e5f1a1166d18e443f8294754f01bf55101ca 100644 (file)
@@ -120,4 +120,31 @@ config SND_BEBOB
           To compile this driver as a module, choose M here: the module
           will be called snd-bebob.
 
+config SND_FIREWIRE_DIGI00X
+       tristate "Digidesign Digi 002/003 family support"
+       select SND_FIREWIRE_LIB
+       select SND_HWDEP
+       help
+        Say Y here to include support for Digidesign Digi 002/003 family.
+         * Digi 002 Console
+         * Digi 002 Rack
+         * Digi 003 Console
+         * Digi 003 Rack
+         * Digi 003 Rack+
+
+        To compile this driver as a module, choose M here: the module
+        will be called snd-firewire-digi00x.
+
+config SND_FIREWIRE_TASCAM
+       tristate "TASCAM FireWire series support"
+       select SND_FIREWIRE_LIB
+       select SND_HWDEP
+       help
+        Say Y here to include support for TASCAM.
+         * FW-1884
+         * FW-1082
+
+        To compile this driver as a module, choose M here: the module
+        will be called snd-firewire-tascam.
+
 endif # SND_FIREWIRE
index 8b37f084b2aba800fb4c82a34089b4957609b2d2..f5fb62551c600cd02664244108470f8613a512ef 100644 (file)
@@ -1,6 +1,5 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
-                        fcp.o cmp.o amdtp.o
-snd-oxfw-objs := oxfw.o
+                        fcp.o cmp.o amdtp-stream.o amdtp-am824.o
 snd-isight-objs := isight.o
 snd-scs1x-objs := scs1x.o
 
@@ -11,3 +10,5 @@ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
 obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
 obj-$(CONFIG_SND_FIREWORKS) += fireworks/
 obj-$(CONFIG_SND_BEBOB) += bebob/
+obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/
+obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/
diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c
new file mode 100644 (file)
index 0000000..bebddc6
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/slab.h>
+
+#include "amdtp-am824.h"
+
+#define CIP_FMT_AM             0x10
+
+/* "Clock-based rate control mode" is just supported. */
+#define AMDTP_FDF_AM824                0x00
+
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND  3093
+
+/*
+ * Several devices look only at the first eight data blocks.
+ * In any case, this is more than enough for the MIDI data rate.
+ */
+#define MAX_MIDI_RX_BLOCKS     8
+
+struct amdtp_am824 {
+       struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8];
+       int midi_fifo_limit;
+       int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8];
+       unsigned int pcm_channels;
+       unsigned int midi_ports;
+
+       u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM];
+       u8 midi_position;
+
+       void (*transfer_samples)(struct amdtp_stream *s,
+                                struct snd_pcm_substream *pcm,
+                                __be32 *buffer, unsigned int frames);
+
+       unsigned int frame_multiplier;
+};
+
+/**
+ * amdtp_am824_set_parameters - set stream parameters
+ * @s: the AMDTP stream to configure
+ * @rate: the sample rate
+ * @pcm_channels: the number of PCM samples in each data block, to be encoded
+ *                as AM824 multi-bit linear audio
+ * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
+ * @double_pcm_frames: one data block transfers two PCM frames
+ *
+ * The parameters must be set before the stream is started, and must not be
+ * changed while the stream is running.
+ */
+int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                              unsigned int pcm_channels,
+                              unsigned int midi_ports,
+                              bool double_pcm_frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int midi_channels;
+       unsigned int i;
+       int err;
+
+       if (amdtp_stream_running(s))
+               return -EINVAL;
+
+       if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM)
+               return -EINVAL;
+
+       midi_channels = DIV_ROUND_UP(midi_ports, 8);
+       if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)
+               return -EINVAL;
+
+       if (WARN_ON(amdtp_stream_running(s)) ||
+           WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) ||
+           WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI))
+               return -EINVAL;
+
+       err = amdtp_stream_set_parameters(s, rate,
+                                         pcm_channels + midi_channels);
+       if (err < 0)
+               return err;
+
+       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+
+       p->pcm_channels = pcm_channels;
+       p->midi_ports = midi_ports;
+
+       /*
+        * In IEC 61883-6, one data block represents one event. In ALSA, one
+        * event equals to one PCM frame. But Dice has a quirk at higher
+        * sampling rate to transfer two PCM frames in one data block.
+        */
+       if (double_pcm_frames)
+               p->frame_multiplier = 2;
+       else
+               p->frame_multiplier = 1;
+
+       /* init the position map for PCM and MIDI channels */
+       for (i = 0; i < pcm_channels; i++)
+               p->pcm_positions[i] = i;
+       p->midi_position = p->pcm_channels;
+
+       /*
+        * We do not know the actual MIDI FIFO size of most devices.  Just
+        * assume two bytes, i.e., one byte can be received over the bus while
+        * the previous one is transmitted over MIDI.
+        * (The value here is adjusted for midi_ratelimit_per_packet().)
+        */
+       p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
+
+/**
+ * amdtp_am824_set_pcm_position - set an index of data channel for a channel
+ *                               of PCM frame
+ * @s: the AMDTP stream
+ * @index: the index of data channel in an data block
+ * @position: the channel of PCM frame
+ */
+void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
+                                unsigned int position)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (index < p->pcm_channels)
+               p->pcm_positions[index] = position;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position);
+
+/**
+ * amdtp_am824_set_midi_position - set a index of data channel for MIDI
+ *                                conformant data channel
+ * @s: the AMDTP stream
+ * @position: the index of data channel in an data block
+ */
+void amdtp_am824_set_midi_position(struct amdtp_stream *s,
+                                  unsigned int position)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       p->midi_position = position;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position);
+
+static void write_pcm_s32(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u32 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[p->pcm_positions[c]] =
+                                       cpu_to_be32((*src >> 8) | 0x40000000);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_s16(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u16 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[p->pcm_positions[c]] =
+                                       cpu_to_be32((*src << 8) | 0x42000000);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void read_pcm_s32(struct amdtp_stream *s,
+                        struct snd_pcm_substream *pcm,
+                        __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       u32 *dst;
+
+       channels = p->pcm_channels;
+       dst  = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8;
+                       dst++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       dst = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s,
+                             __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int i, c, channels = p->pcm_channels;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c)
+                       buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000);
+               buffer += s->data_block_quadlets;
+       }
+}
+
+/**
+ * amdtp_am824_set_pcm_format - set the PCM format
+ * @s: the AMDTP stream to configure
+ * @format: the format of the ALSA PCM device
+ *
+ * The sample format must be set after the other parameters (rate/PCM channels/
+ * MIDI) and before the stream is started, and must not be changed while the
+ * stream is running.
+ */
+void amdtp_am824_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (WARN_ON(amdtp_stream_pcm_running(s)))
+               return;
+
+       switch (format) {
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S16:
+               if (s->direction == AMDTP_OUT_STREAM) {
+                       p->transfer_samples = write_pcm_s16;
+                       break;
+               }
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32:
+               if (s->direction == AMDTP_OUT_STREAM)
+                       p->transfer_samples = write_pcm_s32;
+               else
+                       p->transfer_samples = read_pcm_s32;
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_format);
+
+/**
+ * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream
+ * @s:         the AMDTP stream for AM824 data block, must be initialized.
+ * @runtime:   the PCM substream runtime
+ *
+ */
+int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                      struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
+       if (err < 0)
+               return err;
+
+       /* AM824 in IEC 61883-6 can deliver 24bit data. */
+       return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints);
+
+/**
+ * amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device
+ * @s: the AMDTP stream
+ * @port: index of MIDI port
+ * @midi: the MIDI device to be started, or %NULL to stop the current device
+ *
+ * Call this function on a running isochronous stream to enable the actual
+ * transmission of MIDI data.  This function should be called from the MIDI
+ * device's .trigger callback.
+ */
+void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                             struct snd_rawmidi_substream *midi)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       if (port < p->midi_ports)
+               ACCESS_ONCE(p->midi[port]) = midi;
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
+
+/*
+ * To avoid sending MIDI bytes at too high a rate, assume that the receiving
+ * device has a FIFO, and track how much it is filled.  This values increases
+ * by one whenever we send one byte in a packet, but the FIFO empties at
+ * a constant rate independent of our packet rate.  One packet has syt_interval
+ * samples, so the number of bytes that empty out of the FIFO, per packet(!),
+ * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
+ * fractional values, the values in midi_fifo_used[] are measured in bytes
+ * multiplied by the sample rate.
+ */
+static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_am824 *p = s->protocol;
+       int used;
+
+       used = p->midi_fifo_used[port];
+       if (used == 0) /* common shortcut */
+               return true;
+
+       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
+       used = max(used, 0);
+       p->midi_fifo_used[port] = used;
+
+       return used < p->midi_fifo_limit;
+}
+
+static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_am824 *p = s->protocol;
+
+       p->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
+}
+
+static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                               unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int f, port;
+       u8 *b;
+
+       for (f = 0; f < frames; f++) {
+               b = (u8 *)&buffer[p->midi_position];
+
+               port = (s->data_block_counter + f) % 8;
+               if (f < MAX_MIDI_RX_BLOCKS &&
+                   midi_ratelimit_per_packet(s, port) &&
+                   p->midi[port] != NULL &&
+                   snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) {
+                       midi_rate_use_one_byte(s, port);
+                       b[0] = 0x81;
+               } else {
+                       b[0] = 0x80;
+                       b[1] = 0;
+               }
+               b[2] = 0;
+               b[3] = 0;
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static void read_midi_messages(struct amdtp_stream *s,
+                              __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_am824 *p = s->protocol;
+       unsigned int f, port;
+       int len;
+       u8 *b;
+
+       for (f = 0; f < frames; f++) {
+               port = (s->data_block_counter + f) % 8;
+               b = (u8 *)&buffer[p->midi_position];
+
+               len = b[0] - 0x80;
+               if ((1 <= len) &&  (len <= 3) && (p->midi[port]))
+                       snd_rawmidi_receive(p->midi[port], b + 1, len);
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
+                                          unsigned int data_blocks, unsigned int *syt)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       unsigned int pcm_frames;
+
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks * p->frame_multiplier;
+       } else {
+               write_pcm_silence(s, buffer, data_blocks);
+               pcm_frames = 0;
+       }
+
+       if (p->midi_ports)
+               write_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer,
+                                          unsigned int data_blocks, unsigned int *syt)
+{
+       struct amdtp_am824 *p = s->protocol;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       unsigned int pcm_frames;
+
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks * p->frame_multiplier;
+       } else {
+               pcm_frames = 0;
+       }
+
+       if (p->midi_ports)
+               read_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+/**
+ * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824
+ *                   data block
+ * @s: the AMDTP stream to initialize
+ * @unit: the target of the stream
+ * @dir: the direction of stream
+ * @flags: the packet transmission method to use
+ */
+int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
+                    enum amdtp_stream_direction dir, enum cip_flags flags)
+{
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+
+       if (dir == AMDTP_IN_STREAM)
+               process_data_blocks = process_tx_data_blocks;
+       else
+               process_data_blocks = process_rx_data_blocks;
+
+       return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
+                                process_data_blocks,
+                                sizeof(struct amdtp_am824));
+}
+EXPORT_SYMBOL_GPL(amdtp_am824_init);
diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h
new file mode 100644 (file)
index 0000000..73b07b3
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
+#define SOUND_FIREWIRE_AMDTP_AM824_H_INCLUDED
+
+#include <sound/pcm.h>
+#include <sound/rawmidi.h>
+
+#include "amdtp-stream.h"
+
+#define AM824_IN_PCM_FORMAT_BITS       SNDRV_PCM_FMTBIT_S32
+
+#define AM824_OUT_PCM_FORMAT_BITS      (SNDRV_PCM_FMTBIT_S16 | \
+                                        SNDRV_PCM_FMTBIT_S32)
+
+/*
+ * This module supports maximum 64 PCM channels for one PCM stream
+ * This is for our convenience.
+ */
+#define AM824_MAX_CHANNELS_FOR_PCM     64
+
+/*
+ * AMDTP packet can include channels for MIDI conformant data.
+ * Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
+ * Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
+ *
+ * This module supports maximum 1 MIDI conformant data channels.
+ * Then this AMDTP packets can transfer maximum 8 MIDI data streams.
+ */
+#define AM824_MAX_CHANNELS_FOR_MIDI    1
+
+int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                              unsigned int pcm_channels,
+                              unsigned int midi_ports,
+                              bool double_pcm_frames);
+
+void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
+                                unsigned int position);
+
+void amdtp_am824_set_midi_position(struct amdtp_stream *s,
+                                  unsigned int position);
+
+int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                      struct snd_pcm_runtime *runtime);
+
+void amdtp_am824_set_pcm_format(struct amdtp_stream *s,
+                               snd_pcm_format_t format);
+
+void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                             struct snd_rawmidi_substream *midi);
+
+int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
+                    enum amdtp_stream_direction dir, enum cip_flags flags);
+#endif
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
new file mode 100644 (file)
index 0000000..ed29026
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * Audio and Music Data Transmission Protocol (IEC 61883-6) streams
+ * with Common Isochronous Packet (IEC 61883-1) headers
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firewire.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "amdtp-stream.h"
+
+#define TICKS_PER_CYCLE                3072
+#define CYCLES_PER_SECOND      8000
+#define TICKS_PER_SECOND       (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
+
+#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
+
+/* isochronous header parameters */
+#define ISO_DATA_LENGTH_SHIFT  16
+#define TAG_CIP                        1
+
+/* common isochronous packet header parameters */
+#define CIP_EOH_SHIFT          31
+#define CIP_EOH                        (1u << CIP_EOH_SHIFT)
+#define CIP_EOH_MASK           0x80000000
+#define CIP_SID_SHIFT          24
+#define CIP_SID_MASK           0x3f000000
+#define CIP_DBS_MASK           0x00ff0000
+#define CIP_DBS_SHIFT          16
+#define CIP_DBC_MASK           0x000000ff
+#define CIP_FMT_SHIFT          24
+#define CIP_FMT_MASK           0x3f000000
+#define CIP_FDF_MASK           0x00ff0000
+#define CIP_FDF_SHIFT          16
+#define CIP_SYT_MASK           0x0000ffff
+#define CIP_SYT_NO_INFO                0xffff
+
+/* Audio and Music transfer protocol specific parameters */
+#define CIP_FMT_AM             0x10
+#define AMDTP_FDF_NO_DATA      0xff
+
+/* TODO: make these configurable */
+#define INTERRUPT_INTERVAL     16
+#define QUEUE_LENGTH           48
+
+#define IN_PACKET_HEADER_SIZE  4
+#define OUT_PACKET_HEADER_SIZE 0
+
+static void pcm_period_tasklet(unsigned long data);
+
+/**
+ * amdtp_stream_init - initialize an AMDTP stream structure
+ * @s: the AMDTP stream to initialize
+ * @unit: the target of the stream
+ * @dir: the direction of stream
+ * @flags: the packet transmission method to use
+ * @fmt: the value of fmt field in CIP header
+ * @process_data_blocks: callback handler to process data blocks
+ * @protocol_size: the size to allocate newly for protocol
+ */
+int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
+                     enum amdtp_stream_direction dir, enum cip_flags flags,
+                     unsigned int fmt,
+                     amdtp_stream_process_data_blocks_t process_data_blocks,
+                     unsigned int protocol_size)
+{
+       if (process_data_blocks == NULL)
+               return -EINVAL;
+
+       s->protocol = kzalloc(protocol_size, GFP_KERNEL);
+       if (!s->protocol)
+               return -ENOMEM;
+
+       s->unit = unit;
+       s->direction = dir;
+       s->flags = flags;
+       s->context = ERR_PTR(-1);
+       mutex_init(&s->mutex);
+       tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
+       s->packet_index = 0;
+
+       init_waitqueue_head(&s->callback_wait);
+       s->callbacked = false;
+       s->sync_slave = NULL;
+
+       s->fmt = fmt;
+       s->process_data_blocks = process_data_blocks;
+
+       return 0;
+}
+EXPORT_SYMBOL(amdtp_stream_init);
+
+/**
+ * amdtp_stream_destroy - free stream resources
+ * @s: the AMDTP stream to destroy
+ */
+void amdtp_stream_destroy(struct amdtp_stream *s)
+{
+       WARN_ON(amdtp_stream_running(s));
+       kfree(s->protocol);
+       mutex_destroy(&s->mutex);
+}
+EXPORT_SYMBOL(amdtp_stream_destroy);
+
+const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = {
+       [CIP_SFC_32000]  =  8,
+       [CIP_SFC_44100]  =  8,
+       [CIP_SFC_48000]  =  8,
+       [CIP_SFC_88200]  = 16,
+       [CIP_SFC_96000]  = 16,
+       [CIP_SFC_176400] = 32,
+       [CIP_SFC_192000] = 32,
+};
+EXPORT_SYMBOL(amdtp_syt_intervals);
+
+const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
+       [CIP_SFC_32000]  =  32000,
+       [CIP_SFC_44100]  =  44100,
+       [CIP_SFC_48000]  =  48000,
+       [CIP_SFC_88200]  =  88200,
+       [CIP_SFC_96000]  =  96000,
+       [CIP_SFC_176400] = 176400,
+       [CIP_SFC_192000] = 192000,
+};
+EXPORT_SYMBOL(amdtp_rate_table);
+
+/**
+ * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
+ * @s:         the AMDTP stream, which must be initialized.
+ * @runtime:   the PCM substream runtime
+ */
+int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                       struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       /*
+        * Currently firewire-lib processes 16 packets in one software
+        * interrupt callback. This equals to 2msec but actually the
+        * interval of the interrupts has a jitter.
+        * Additionally, even if adding a constraint to fit period size to
+        * 2msec, actual calculated frames per period doesn't equal to 2msec,
+        * depending on sampling rate.
+        * Anyway, the interval to call snd_pcm_period_elapsed() cannot 2msec.
+        * Here let us use 5msec for safe period interrupt.
+        */
+       err = snd_pcm_hw_constraint_minmax(runtime,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+                                          5000, UINT_MAX);
+       if (err < 0)
+               goto end;
+
+       /* Non-Blocking stream has no more constraints */
+       if (!(s->flags & CIP_BLOCKING))
+               goto end;
+
+       /*
+        * One AMDTP packet can include some frames. In blocking mode, the
+        * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
+        * depending on its sampling rate. For accurate period interrupt, it's
+        * preferrable to align period/buffer sizes to current SYT_INTERVAL.
+        *
+        * TODO: These constraints can be improved with proper rules.
+        * Currently apply LCM of SYT_INTERVALs.
+        */
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
+       if (err < 0)
+               goto end;
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+end:
+       return err;
+}
+EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints);
+
+/**
+ * amdtp_stream_set_parameters - set stream parameters
+ * @s: the AMDTP stream to configure
+ * @rate: the sample rate
+ * @data_block_quadlets: the size of a data block in quadlet unit
+ *
+ * The parameters must be set before the stream is started, and must not be
+ * changed while the stream is running.
+ */
+int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                               unsigned int data_block_quadlets)
+{
+       unsigned int sfc;
+
+       for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc) {
+               if (amdtp_rate_table[sfc] == rate)
+                       break;
+       }
+       if (sfc == ARRAY_SIZE(amdtp_rate_table))
+               return -EINVAL;
+
+       s->sfc = sfc;
+       s->data_block_quadlets = data_block_quadlets;
+       s->syt_interval = amdtp_syt_intervals[sfc];
+
+       /* default buffering in the device */
+       s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+       if (s->flags & CIP_BLOCKING)
+               /* additional buffering needed to adjust for no-data packets */
+               s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
+
+       return 0;
+}
+EXPORT_SYMBOL(amdtp_stream_set_parameters);
+
+/**
+ * amdtp_stream_get_max_payload - get the stream's packet size
+ * @s: the AMDTP stream
+ *
+ * This function must not be called before the stream has been configured
+ * with amdtp_stream_set_parameters().
+ */
+unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
+{
+       unsigned int multiplier = 1;
+
+       if (s->flags & CIP_JUMBO_PAYLOAD)
+               multiplier = 5;
+
+       return 8 + s->syt_interval * s->data_block_quadlets * 4 * multiplier;
+}
+EXPORT_SYMBOL(amdtp_stream_get_max_payload);
+
+/**
+ * amdtp_stream_pcm_prepare - prepare PCM device for running
+ * @s: the AMDTP stream
+ *
+ * This function should be called from the PCM device's .prepare callback.
+ */
+void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
+{
+       tasklet_kill(&s->period_tasklet);
+       s->pcm_buffer_pointer = 0;
+       s->pcm_period_pointer = 0;
+       s->pointer_flush = true;
+}
+EXPORT_SYMBOL(amdtp_stream_pcm_prepare);
+
+static unsigned int calculate_data_blocks(struct amdtp_stream *s,
+                                         unsigned int syt)
+{
+       unsigned int phase, data_blocks;
+
+       /* Blocking mode. */
+       if (s->flags & CIP_BLOCKING) {
+               /* This module generate empty packet for 'no data'. */
+               if (syt == CIP_SYT_NO_INFO)
+                       data_blocks = 0;
+               else
+                       data_blocks = s->syt_interval;
+       /* Non-blocking mode. */
+       } else {
+               if (!cip_sfc_is_base_44100(s->sfc)) {
+                       /* Sample_rate / 8000 is an integer, and precomputed. */
+                       data_blocks = s->data_block_state;
+               } else {
+                       phase = s->data_block_state;
+
+               /*
+                * This calculates the number of data blocks per packet so that
+                * 1) the overall rate is correct and exactly synchronized to
+                *    the bus clock, and
+                * 2) packets with a rounded-up number of blocks occur as early
+                *    as possible in the sequence (to prevent underruns of the
+                *    device's buffer).
+                */
+                       if (s->sfc == CIP_SFC_44100)
+                               /* 6 6 5 6 5 6 5 ... */
+                               data_blocks = 5 + ((phase & 1) ^
+                                                  (phase == 0 || phase >= 40));
+                       else
+                               /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */
+                               data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
+                       if (++phase >= (80 >> (s->sfc >> 1)))
+                               phase = 0;
+                       s->data_block_state = phase;
+               }
+       }
+
+       return data_blocks;
+}
+
+static unsigned int calculate_syt(struct amdtp_stream *s,
+                                 unsigned int cycle)
+{
+       unsigned int syt_offset, phase, index, syt;
+
+       if (s->last_syt_offset < TICKS_PER_CYCLE) {
+               if (!cip_sfc_is_base_44100(s->sfc))
+                       syt_offset = s->last_syt_offset + s->syt_offset_state;
+               else {
+               /*
+                * The time, in ticks, of the n'th SYT_INTERVAL sample is:
+                *   n * SYT_INTERVAL * 24576000 / sample_rate
+                * Modulo TICKS_PER_CYCLE, the difference between successive
+                * elements is about 1386.23.  Rounding the results of this
+                * formula to the SYT precision results in a sequence of
+                * differences that begins with:
+                *   1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ...
+                * This code generates _exactly_ the same sequence.
+                */
+                       phase = s->syt_offset_state;
+                       index = phase % 13;
+                       syt_offset = s->last_syt_offset;
+                       syt_offset += 1386 + ((index && !(index & 3)) ||
+                                             phase == 146);
+                       if (++phase >= 147)
+                               phase = 0;
+                       s->syt_offset_state = phase;
+               }
+       } else
+               syt_offset = s->last_syt_offset - TICKS_PER_CYCLE;
+       s->last_syt_offset = syt_offset;
+
+       if (syt_offset < TICKS_PER_CYCLE) {
+               syt_offset += s->transfer_delay;
+               syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
+               syt += syt_offset % TICKS_PER_CYCLE;
+
+               return syt & CIP_SYT_MASK;
+       } else {
+               return CIP_SYT_NO_INFO;
+       }
+}
+
+static void update_pcm_pointers(struct amdtp_stream *s,
+                               struct snd_pcm_substream *pcm,
+                               unsigned int frames)
+{
+       unsigned int ptr;
+
+       ptr = s->pcm_buffer_pointer + frames;
+       if (ptr >= pcm->runtime->buffer_size)
+               ptr -= pcm->runtime->buffer_size;
+       ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
+
+       s->pcm_period_pointer += frames;
+       if (s->pcm_period_pointer >= pcm->runtime->period_size) {
+               s->pcm_period_pointer -= pcm->runtime->period_size;
+               s->pointer_flush = false;
+               tasklet_hi_schedule(&s->period_tasklet);
+       }
+}
+
+static void pcm_period_tasklet(unsigned long data)
+{
+       struct amdtp_stream *s = (void *)data;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+
+       if (pcm)
+               snd_pcm_period_elapsed(pcm);
+}
+
+static int queue_packet(struct amdtp_stream *s,
+                       unsigned int header_length,
+                       unsigned int payload_length, bool skip)
+{
+       struct fw_iso_packet p = {0};
+       int err = 0;
+
+       if (IS_ERR(s->context))
+               goto end;
+
+       p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
+       p.tag = TAG_CIP;
+       p.header_length = header_length;
+       p.payload_length = (!skip) ? payload_length : 0;
+       p.skip = skip;
+       err = fw_iso_context_queue(s->context, &p, &s->buffer.iso_buffer,
+                                  s->buffer.packets[s->packet_index].offset);
+       if (err < 0) {
+               dev_err(&s->unit->device, "queueing error: %d\n", err);
+               goto end;
+       }
+
+       if (++s->packet_index >= QUEUE_LENGTH)
+               s->packet_index = 0;
+end:
+       return err;
+}
+
+static inline int queue_out_packet(struct amdtp_stream *s,
+                                  unsigned int payload_length, bool skip)
+{
+       return queue_packet(s, OUT_PACKET_HEADER_SIZE,
+                           payload_length, skip);
+}
+
+static inline int queue_in_packet(struct amdtp_stream *s)
+{
+       return queue_packet(s, IN_PACKET_HEADER_SIZE,
+                           amdtp_stream_get_max_payload(s), false);
+}
+
+static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
+                            unsigned int syt)
+{
+       __be32 *buffer;
+       unsigned int payload_length;
+       unsigned int pcm_frames;
+       struct snd_pcm_substream *pcm;
+
+       buffer = s->buffer.packets[s->packet_index].buffer;
+       pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
+
+       buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
+                               (s->data_block_quadlets << CIP_DBS_SHIFT) |
+                               s->data_block_counter);
+       buffer[1] = cpu_to_be32(CIP_EOH |
+                               ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
+                               ((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
+                               (syt & CIP_SYT_MASK));
+
+       s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+
+       payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
+       if (queue_out_packet(s, payload_length, false) < 0)
+               return -EIO;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm && pcm_frames > 0)
+               update_pcm_pointers(s, pcm, pcm_frames);
+
+       /* No need to return the number of handled data blocks. */
+       return 0;
+}
+
+static int handle_in_packet(struct amdtp_stream *s,
+                           unsigned int payload_quadlets, __be32 *buffer,
+                           unsigned int *data_blocks, unsigned int syt)
+{
+       u32 cip_header[2];
+       unsigned int fmt, fdf;
+       unsigned int data_block_quadlets, data_block_counter, dbc_interval;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
+       bool lost;
+
+       cip_header[0] = be32_to_cpu(buffer[0]);
+       cip_header[1] = be32_to_cpu(buffer[1]);
+
+       /*
+        * This module supports 'Two-quadlet CIP header with SYT field'.
+        * For convenience, also check FMT field is AM824 or not.
+        */
+       if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
+           ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) {
+               dev_info_ratelimited(&s->unit->device,
+                               "Invalid CIP header for AMDTP: %08X:%08X\n",
+                               cip_header[0], cip_header[1]);
+               *data_blocks = 0;
+               pcm_frames = 0;
+               goto end;
+       }
+
+       /* Check valid protocol or not. */
+       fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT;
+       if (fmt != s->fmt) {
+               dev_info_ratelimited(&s->unit->device,
+                                    "Detect unexpected protocol: %08x %08x\n",
+                                    cip_header[0], cip_header[1]);
+               *data_blocks = 0;
+               pcm_frames = 0;
+               goto end;
+       }
+
+       /* Calculate data blocks */
+       fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT;
+       if (payload_quadlets < 3 ||
+           (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) {
+               *data_blocks = 0;
+       } else {
+               data_block_quadlets =
+                       (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
+               /* avoid division by zero */
+               if (data_block_quadlets == 0) {
+                       dev_err(&s->unit->device,
+                               "Detect invalid value in dbs field: %08X\n",
+                               cip_header[0]);
+                       return -EPROTO;
+               }
+               if (s->flags & CIP_WRONG_DBS)
+                       data_block_quadlets = s->data_block_quadlets;
+
+               *data_blocks = (payload_quadlets - 2) / data_block_quadlets;
+       }
+
+       /* Check data block counter continuity */
+       data_block_counter = cip_header[0] & CIP_DBC_MASK;
+       if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
+           s->data_block_counter != UINT_MAX)
+               data_block_counter = s->data_block_counter;
+
+       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
+            data_block_counter == s->tx_first_dbc) ||
+           s->data_block_counter == UINT_MAX) {
+               lost = false;
+       } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
+               lost = data_block_counter != s->data_block_counter;
+       } else {
+               if ((*data_blocks > 0) && (s->tx_dbc_interval > 0))
+                       dbc_interval = s->tx_dbc_interval;
+               else
+                       dbc_interval = *data_blocks;
+
+               lost = data_block_counter !=
+                      ((s->data_block_counter + dbc_interval) & 0xff);
+       }
+
+       if (lost) {
+               dev_err(&s->unit->device,
+                       "Detect discontinuity of CIP: %02X %02X\n",
+                       s->data_block_counter, data_block_counter);
+               return -EIO;
+       }
+
+       pcm_frames = s->process_data_blocks(s, buffer + 2, *data_blocks, &syt);
+
+       if (s->flags & CIP_DBC_IS_END_EVENT)
+               s->data_block_counter = data_block_counter;
+       else
+               s->data_block_counter =
+                               (data_block_counter + *data_blocks) & 0xff;
+end:
+       if (queue_in_packet(s) < 0)
+               return -EIO;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm && pcm_frames > 0)
+               update_pcm_pointers(s, pcm, pcm_frames);
+
+       return 0;
+}
+
+static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
+                               size_t header_length, void *header,
+                               void *private_data)
+{
+       struct amdtp_stream *s = private_data;
+       unsigned int i, syt, packets = header_length / 4;
+       unsigned int data_blocks;
+
+       if (s->packet_index < 0)
+               return;
+
+       /*
+        * Compute the cycle of the last queued packet.
+        * (We need only the four lowest bits for the SYT, so we can ignore
+        * that bits 0-11 must wrap around at 3072.)
+        */
+       cycle += QUEUE_LENGTH - packets;
+
+       for (i = 0; i < packets; ++i) {
+               syt = calculate_syt(s, ++cycle);
+               data_blocks = calculate_data_blocks(s, syt);
+
+               if (handle_out_packet(s, data_blocks, syt) < 0) {
+                       s->packet_index = -1;
+                       amdtp_stream_pcm_abort(s);
+                       return;
+               }
+       }
+
+       fw_iso_context_queue_flush(s->context);
+}
+
+static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
+                              size_t header_length, void *header,
+                              void *private_data)
+{
+       struct amdtp_stream *s = private_data;
+       unsigned int p, syt, packets;
+       unsigned int payload_quadlets, max_payload_quadlets;
+       unsigned int data_blocks;
+       __be32 *buffer, *headers = header;
+
+       if (s->packet_index < 0)
+               return;
+
+       /* The number of packets in buffer */
+       packets = header_length / IN_PACKET_HEADER_SIZE;
+
+       /* For buffer-over-run prevention. */
+       max_payload_quadlets = amdtp_stream_get_max_payload(s) / 4;
+
+       for (p = 0; p < packets; p++) {
+               buffer = s->buffer.packets[s->packet_index].buffer;
+
+               /* The number of quadlets in this packet */
+               payload_quadlets =
+                       (be32_to_cpu(headers[p]) >> ISO_DATA_LENGTH_SHIFT) / 4;
+               if (payload_quadlets > max_payload_quadlets) {
+                       dev_err(&s->unit->device,
+                               "Detect jumbo payload: %02x %02x\n",
+                               payload_quadlets, max_payload_quadlets);
+                       s->packet_index = -1;
+                       break;
+               }
+
+               syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
+               if (handle_in_packet(s, payload_quadlets, buffer,
+                                               &data_blocks, syt) < 0) {
+                       s->packet_index = -1;
+                       break;
+               }
+
+               /* Process sync slave stream */
+               if (s->sync_slave && s->sync_slave->callbacked) {
+                       if (handle_out_packet(s->sync_slave,
+                                             data_blocks, syt) < 0) {
+                               s->packet_index = -1;
+                               break;
+                       }
+               }
+       }
+
+       /* Queueing error or detecting discontinuity */
+       if (s->packet_index < 0) {
+               amdtp_stream_pcm_abort(s);
+
+               /* Abort sync slave. */
+               if (s->sync_slave) {
+                       s->sync_slave->packet_index = -1;
+                       amdtp_stream_pcm_abort(s->sync_slave);
+               }
+               return;
+       }
+
+       /* when sync to device, flush the packets for slave stream */
+       if (s->sync_slave && s->sync_slave->callbacked)
+               fw_iso_context_queue_flush(s->sync_slave->context);
+
+       fw_iso_context_queue_flush(s->context);
+}
+
+/* processing is done by master callback */
+static void slave_stream_callback(struct fw_iso_context *context, u32 cycle,
+                                 size_t header_length, void *header,
+                                 void *private_data)
+{
+       return;
+}
+
+/* this is executed one time */
+static void amdtp_stream_first_callback(struct fw_iso_context *context,
+                                       u32 cycle, size_t header_length,
+                                       void *header, void *private_data)
+{
+       struct amdtp_stream *s = private_data;
+
+       /*
+        * For in-stream, first packet has come.
+        * For out-stream, prepared to transmit first packet
+        */
+       s->callbacked = true;
+       wake_up(&s->callback_wait);
+
+       if (s->direction == AMDTP_IN_STREAM)
+               context->callback.sc = in_stream_callback;
+       else if (s->flags & CIP_SYNC_TO_DEVICE)
+               context->callback.sc = slave_stream_callback;
+       else
+               context->callback.sc = out_stream_callback;
+
+       context->callback.sc(context, cycle, header_length, header, s);
+}
+
+/**
+ * amdtp_stream_start - start transferring packets
+ * @s: the AMDTP stream to start
+ * @channel: the isochronous channel on the bus
+ * @speed: firewire speed code
+ *
+ * The stream cannot be started until it has been configured with
+ * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
+ * device can be started.
+ */
+int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
+{
+       static const struct {
+               unsigned int data_block;
+               unsigned int syt_offset;
+       } initial_state[] = {
+               [CIP_SFC_32000]  = {  4, 3072 },
+               [CIP_SFC_48000]  = {  6, 1024 },
+               [CIP_SFC_96000]  = { 12, 1024 },
+               [CIP_SFC_192000] = { 24, 1024 },
+               [CIP_SFC_44100]  = {  0,   67 },
+               [CIP_SFC_88200]  = {  0,   67 },
+               [CIP_SFC_176400] = {  0,   67 },
+       };
+       unsigned int header_size;
+       enum dma_data_direction dir;
+       int type, tag, err;
+
+       mutex_lock(&s->mutex);
+
+       if (WARN_ON(amdtp_stream_running(s) ||
+                   (s->data_block_quadlets < 1))) {
+               err = -EBADFD;
+               goto err_unlock;
+       }
+
+       if (s->direction == AMDTP_IN_STREAM &&
+           s->flags & CIP_SKIP_INIT_DBC_CHECK)
+               s->data_block_counter = UINT_MAX;
+       else
+               s->data_block_counter = 0;
+       s->data_block_state = initial_state[s->sfc].data_block;
+       s->syt_offset_state = initial_state[s->sfc].syt_offset;
+       s->last_syt_offset = TICKS_PER_CYCLE;
+
+       /* initialize packet buffer */
+       if (s->direction == AMDTP_IN_STREAM) {
+               dir = DMA_FROM_DEVICE;
+               type = FW_ISO_CONTEXT_RECEIVE;
+               header_size = IN_PACKET_HEADER_SIZE;
+       } else {
+               dir = DMA_TO_DEVICE;
+               type = FW_ISO_CONTEXT_TRANSMIT;
+               header_size = OUT_PACKET_HEADER_SIZE;
+       }
+       err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
+                                     amdtp_stream_get_max_payload(s), dir);
+       if (err < 0)
+               goto err_unlock;
+
+       s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
+                                          type, channel, speed, header_size,
+                                          amdtp_stream_first_callback, s);
+       if (IS_ERR(s->context)) {
+               err = PTR_ERR(s->context);
+               if (err == -EBUSY)
+                       dev_err(&s->unit->device,
+                               "no free stream on this controller\n");
+               goto err_buffer;
+       }
+
+       amdtp_stream_update(s);
+
+       s->packet_index = 0;
+       do {
+               if (s->direction == AMDTP_IN_STREAM)
+                       err = queue_in_packet(s);
+               else
+                       err = queue_out_packet(s, 0, true);
+               if (err < 0)
+                       goto err_context;
+       } while (s->packet_index > 0);
+
+       /* NOTE: TAG1 matches CIP. This just affects in stream. */
+       tag = FW_ISO_CONTEXT_MATCH_TAG1;
+       if (s->flags & CIP_EMPTY_WITH_TAG0)
+               tag |= FW_ISO_CONTEXT_MATCH_TAG0;
+
+       s->callbacked = false;
+       err = fw_iso_context_start(s->context, -1, 0, tag);
+       if (err < 0)
+               goto err_context;
+
+       mutex_unlock(&s->mutex);
+
+       return 0;
+
+err_context:
+       fw_iso_context_destroy(s->context);
+       s->context = ERR_PTR(-1);
+err_buffer:
+       iso_packets_buffer_destroy(&s->buffer, s->unit);
+err_unlock:
+       mutex_unlock(&s->mutex);
+
+       return err;
+}
+EXPORT_SYMBOL(amdtp_stream_start);
+
+/**
+ * amdtp_stream_pcm_pointer - get the PCM buffer position
+ * @s: the AMDTP stream that transports the PCM data
+ *
+ * Returns the current buffer position, in frames.
+ */
+unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
+{
+       /* this optimization is allowed to be racy */
+       if (s->pointer_flush && amdtp_stream_running(s))
+               fw_iso_context_flush_completions(s->context);
+       else
+               s->pointer_flush = true;
+
+       return ACCESS_ONCE(s->pcm_buffer_pointer);
+}
+EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
+
+/**
+ * amdtp_stream_update - update the stream after a bus reset
+ * @s: the AMDTP stream
+ */
+void amdtp_stream_update(struct amdtp_stream *s)
+{
+       /* Precomputing. */
+       ACCESS_ONCE(s->source_node_id_field) =
+               (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) &
+                                                               CIP_SID_MASK;
+}
+EXPORT_SYMBOL(amdtp_stream_update);
+
+/**
+ * amdtp_stream_stop - stop sending packets
+ * @s: the AMDTP stream to stop
+ *
+ * All PCM and MIDI devices of the stream must be stopped before the stream
+ * itself can be stopped.
+ */
+void amdtp_stream_stop(struct amdtp_stream *s)
+{
+       mutex_lock(&s->mutex);
+
+       if (!amdtp_stream_running(s)) {
+               mutex_unlock(&s->mutex);
+               return;
+       }
+
+       tasklet_kill(&s->period_tasklet);
+       fw_iso_context_stop(s->context);
+       fw_iso_context_destroy(s->context);
+       s->context = ERR_PTR(-1);
+       iso_packets_buffer_destroy(&s->buffer, s->unit);
+
+       s->callbacked = false;
+
+       mutex_unlock(&s->mutex);
+}
+EXPORT_SYMBOL(amdtp_stream_stop);
+
+/**
+ * amdtp_stream_pcm_abort - abort the running PCM device
+ * @s: the AMDTP stream about to be stopped
+ *
+ * If the isochronous stream needs to be stopped asynchronously, call this
+ * function first to stop the PCM device.
+ */
+void amdtp_stream_pcm_abort(struct amdtp_stream *s)
+{
+       struct snd_pcm_substream *pcm;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm)
+               snd_pcm_stop_xrun(pcm);
+}
+EXPORT_SYMBOL(amdtp_stream_pcm_abort);
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
new file mode 100644 (file)
index 0000000..8775704
--- /dev/null
@@ -0,0 +1,258 @@
+#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
+#define SOUND_FIREWIRE_AMDTP_H_INCLUDED
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <sound/asound.h>
+#include "packets-buffer.h"
+
+/**
+ * enum cip_flags - describes details of the streaming protocol
+ * @CIP_NONBLOCKING: In non-blocking mode, each packet contains
+ *     sample_rate/8000 samples, with rounding up or down to adjust
+ *     for clock skew and left-over fractional samples.  This should
+ *     be used if supported by the device.
+ * @CIP_BLOCKING: In blocking mode, each packet contains either zero or
+ *     SYT_INTERVAL samples, with these two types alternating so that
+ *     the overall sample rate comes out right.
+ * @CIP_SYNC_TO_DEVICE: In sync to device mode, time stamp in out packets is
+ *     generated by in packets. Defaultly this driver generates timestamp.
+ * @CIP_EMPTY_WITH_TAG0: Only for in-stream. Empty in-packets have TAG0.
+ * @CIP_DBC_IS_END_EVENT: Only for in-stream. The value of dbc in an in-packet
+ *     corresponds to the end of event in the packet. Out of IEC 61883.
+ * @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets.
+ *     The value of data_block_quadlets is used instead of reported value.
+ * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream.  Packets with zero in dbc is
+ *     skipped for detecting discontinuity.
+ * @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first
+ *     packet is not continuous from an initial value.
+ * @CIP_EMPTY_HAS_WRONG_DBC: Only for in-stream. The value of dbc in empty
+ *     packet is wrong but the others are correct.
+ * @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an
+ *     packet is larger than IEC 61883-6 defines. Current implementation
+ *     allows 5 times as large as IEC 61883-6 defines.
+ */
+enum cip_flags {
+       CIP_NONBLOCKING         = 0x00,
+       CIP_BLOCKING            = 0x01,
+       CIP_SYNC_TO_DEVICE      = 0x02,
+       CIP_EMPTY_WITH_TAG0     = 0x04,
+       CIP_DBC_IS_END_EVENT    = 0x08,
+       CIP_WRONG_DBS           = 0x10,
+       CIP_SKIP_DBC_ZERO_CHECK = 0x20,
+       CIP_SKIP_INIT_DBC_CHECK = 0x40,
+       CIP_EMPTY_HAS_WRONG_DBC = 0x80,
+       CIP_JUMBO_PAYLOAD       = 0x100,
+};
+
+/**
+ * enum cip_sfc - supported Sampling Frequency Codes (SFCs)
+ * @CIP_SFC_32000:   32,000 data blocks
+ * @CIP_SFC_44100:   44,100 data blocks
+ * @CIP_SFC_48000:   48,000 data blocks
+ * @CIP_SFC_88200:   88,200 data blocks
+ * @CIP_SFC_96000:   96,000 data blocks
+ * @CIP_SFC_176400: 176,400 data blocks
+ * @CIP_SFC_192000: 192,000 data blocks
+ * @CIP_SFC_COUNT: the number of supported SFCs
+ *
+ * These values are used to show nominal Sampling Frequency Code in
+ * Format Dependent Field (FDF) of AMDTP packet header. In IEC 61883-6:2002,
+ * this code means the number of events per second. Actually the code
+ * represents the number of data blocks transferred per second in an AMDTP
+ * stream.
+ *
+ * In IEC 61883-6:2005, some extensions were added to support more types of
+ * data such as 'One Bit LInear Audio', therefore the meaning of SFC became
+ * different depending on the types.
+ *
+ * Currently our implementation is compatible with IEC 61883-6:2002.
+ */
+enum cip_sfc {
+       CIP_SFC_32000  = 0,
+       CIP_SFC_44100  = 1,
+       CIP_SFC_48000  = 2,
+       CIP_SFC_88200  = 3,
+       CIP_SFC_96000  = 4,
+       CIP_SFC_176400 = 5,
+       CIP_SFC_192000 = 6,
+       CIP_SFC_COUNT
+};
+
+struct fw_unit;
+struct fw_iso_context;
+struct snd_pcm_substream;
+struct snd_pcm_runtime;
+
+enum amdtp_stream_direction {
+       AMDTP_OUT_STREAM = 0,
+       AMDTP_IN_STREAM
+};
+
+struct amdtp_stream;
+typedef unsigned int (*amdtp_stream_process_data_blocks_t)(
+                                               struct amdtp_stream *s,
+                                               __be32 *buffer,
+                                               unsigned int data_blocks,
+                                               unsigned int *syt);
+struct amdtp_stream {
+       struct fw_unit *unit;
+       enum cip_flags flags;
+       enum amdtp_stream_direction direction;
+       struct mutex mutex;
+
+       /* For packet processing. */
+       struct fw_iso_context *context;
+       struct iso_packets_buffer buffer;
+       int packet_index;
+
+       /* For CIP headers. */
+       unsigned int source_node_id_field;
+       unsigned int data_block_quadlets;
+       unsigned int data_block_counter;
+       unsigned int fmt;
+       unsigned int fdf;
+       /* quirk: fixed interval of dbc between previos/current packets. */
+       unsigned int tx_dbc_interval;
+       /* quirk: indicate the value of dbc field in a first packet. */
+       unsigned int tx_first_dbc;
+
+       /* Internal flags. */
+       enum cip_sfc sfc;
+       unsigned int syt_interval;
+       unsigned int transfer_delay;
+       unsigned int data_block_state;
+       unsigned int last_syt_offset;
+       unsigned int syt_offset_state;
+
+       /* For a PCM substream processing. */
+       struct snd_pcm_substream *pcm;
+       struct tasklet_struct period_tasklet;
+       unsigned int pcm_buffer_pointer;
+       unsigned int pcm_period_pointer;
+       bool pointer_flush;
+
+       /* To wait for first packet. */
+       bool callbacked;
+       wait_queue_head_t callback_wait;
+       struct amdtp_stream *sync_slave;
+
+       /* For backends to process data blocks. */
+       void *protocol;
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+};
+
+int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
+                     enum amdtp_stream_direction dir, enum cip_flags flags,
+                     unsigned int fmt,
+                     amdtp_stream_process_data_blocks_t process_data_blocks,
+                     unsigned int protocol_size);
+void amdtp_stream_destroy(struct amdtp_stream *s);
+
+int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                               unsigned int data_block_quadlets);
+unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
+
+int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed);
+void amdtp_stream_update(struct amdtp_stream *s);
+void amdtp_stream_stop(struct amdtp_stream *s);
+
+int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                       struct snd_pcm_runtime *runtime);
+
+void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
+unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
+void amdtp_stream_pcm_abort(struct amdtp_stream *s);
+
+extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
+extern const unsigned int amdtp_rate_table[CIP_SFC_COUNT];
+
+/**
+ * amdtp_stream_running - check stream is running or not
+ * @s: the AMDTP stream
+ *
+ * If this function returns true, the stream is running.
+ */
+static inline bool amdtp_stream_running(struct amdtp_stream *s)
+{
+       return !IS_ERR(s->context);
+}
+
+/**
+ * amdtp_streaming_error - check for streaming error
+ * @s: the AMDTP stream
+ *
+ * If this function returns true, the stream's packet queue has stopped due to
+ * an asynchronous error.
+ */
+static inline bool amdtp_streaming_error(struct amdtp_stream *s)
+{
+       return s->packet_index < 0;
+}
+
+/**
+ * amdtp_stream_pcm_running - check PCM substream is running or not
+ * @s: the AMDTP stream
+ *
+ * If this function returns true, PCM substream in the AMDTP stream is running.
+ */
+static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s)
+{
+       return !!s->pcm;
+}
+
+/**
+ * amdtp_stream_pcm_trigger - start/stop playback from a PCM device
+ * @s: the AMDTP stream
+ * @pcm: the PCM device to be started, or %NULL to stop the current device
+ *
+ * Call this function on a running isochronous stream to enable the actual
+ * transmission of PCM data.  This function should be called from the PCM
+ * device's .trigger callback.
+ */
+static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s,
+                                           struct snd_pcm_substream *pcm)
+{
+       ACCESS_ONCE(s->pcm) = pcm;
+}
+
+static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
+{
+       return sfc & 1;
+}
+
+static inline void amdtp_stream_set_sync(enum cip_flags sync_mode,
+                                        struct amdtp_stream *master,
+                                        struct amdtp_stream *slave)
+{
+       if (sync_mode == CIP_SYNC_TO_DEVICE) {
+               master->flags |= CIP_SYNC_TO_DEVICE;
+               slave->flags |= CIP_SYNC_TO_DEVICE;
+               master->sync_slave = slave;
+       } else {
+               master->flags &= ~CIP_SYNC_TO_DEVICE;
+               slave->flags &= ~CIP_SYNC_TO_DEVICE;
+               master->sync_slave = NULL;
+       }
+
+       slave->sync_slave = NULL;
+}
+
+/**
+ * amdtp_stream_wait_callback - sleep till callbacked or timeout
+ * @s: the AMDTP stream
+ * @timeout: msec till timeout
+ *
+ * If this function return false, the AMDTP stream should be stopped.
+ */
+static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
+                                             unsigned int timeout)
+{
+       return wait_event_timeout(s->callback_wait,
+                                 s->callbacked == true,
+                                 msecs_to_jiffies(timeout)) > 0;
+}
+
+#endif
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
deleted file mode 100644 (file)
index 2a153d2..0000000
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*
- * Audio and Music Data Transmission Protocol (IEC 61883-6) streams
- * with Common Isochronous Packet (IEC 61883-1) headers
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/firewire.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/rawmidi.h>
-#include "amdtp.h"
-
-#define TICKS_PER_CYCLE                3072
-#define CYCLES_PER_SECOND      8000
-#define TICKS_PER_SECOND       (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
-
-/*
- * Nominally 3125 bytes/second, but the MIDI port's clock might be
- * 1% too slow, and the bus clock 100 ppm too fast.
- */
-#define MIDI_BYTES_PER_SECOND  3093
-
-/*
- * Several devices look only at the first eight data blocks.
- * In any case, this is more than enough for the MIDI data rate.
- */
-#define MAX_MIDI_RX_BLOCKS     8
-
-#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 microseconds */
-
-/* isochronous header parameters */
-#define ISO_DATA_LENGTH_SHIFT  16
-#define TAG_CIP                        1
-
-/* common isochronous packet header parameters */
-#define CIP_EOH_SHIFT          31
-#define CIP_EOH                        (1u << CIP_EOH_SHIFT)
-#define CIP_EOH_MASK           0x80000000
-#define CIP_SID_SHIFT          24
-#define CIP_SID_MASK           0x3f000000
-#define CIP_DBS_MASK           0x00ff0000
-#define CIP_DBS_SHIFT          16
-#define CIP_DBC_MASK           0x000000ff
-#define CIP_FMT_SHIFT          24
-#define CIP_FMT_MASK           0x3f000000
-#define CIP_FDF_MASK           0x00ff0000
-#define CIP_FDF_SHIFT          16
-#define CIP_SYT_MASK           0x0000ffff
-#define CIP_SYT_NO_INFO                0xffff
-
-/*
- * Audio and Music transfer protocol specific parameters
- * only "Clock-based rate control mode" is supported
- */
-#define CIP_FMT_AM             (0x10 << CIP_FMT_SHIFT)
-#define AMDTP_FDF_AM824                (0 << (CIP_FDF_SHIFT + 3))
-#define AMDTP_FDF_NO_DATA      0xff
-
-/* TODO: make these configurable */
-#define INTERRUPT_INTERVAL     16
-#define QUEUE_LENGTH           48
-
-#define IN_PACKET_HEADER_SIZE  4
-#define OUT_PACKET_HEADER_SIZE 0
-
-static void pcm_period_tasklet(unsigned long data);
-
-/**
- * amdtp_stream_init - initialize an AMDTP stream structure
- * @s: the AMDTP stream to initialize
- * @unit: the target of the stream
- * @dir: the direction of stream
- * @flags: the packet transmission method to use
- */
-int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
-                     enum amdtp_stream_direction dir, enum cip_flags flags)
-{
-       s->unit = unit;
-       s->direction = dir;
-       s->flags = flags;
-       s->context = ERR_PTR(-1);
-       mutex_init(&s->mutex);
-       tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
-       s->packet_index = 0;
-
-       init_waitqueue_head(&s->callback_wait);
-       s->callbacked = false;
-       s->sync_slave = NULL;
-
-       return 0;
-}
-EXPORT_SYMBOL(amdtp_stream_init);
-
-/**
- * amdtp_stream_destroy - free stream resources
- * @s: the AMDTP stream to destroy
- */
-void amdtp_stream_destroy(struct amdtp_stream *s)
-{
-       WARN_ON(amdtp_stream_running(s));
-       mutex_destroy(&s->mutex);
-}
-EXPORT_SYMBOL(amdtp_stream_destroy);
-
-const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = {
-       [CIP_SFC_32000]  =  8,
-       [CIP_SFC_44100]  =  8,
-       [CIP_SFC_48000]  =  8,
-       [CIP_SFC_88200]  = 16,
-       [CIP_SFC_96000]  = 16,
-       [CIP_SFC_176400] = 32,
-       [CIP_SFC_192000] = 32,
-};
-EXPORT_SYMBOL(amdtp_syt_intervals);
-
-const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
-       [CIP_SFC_32000]  =  32000,
-       [CIP_SFC_44100]  =  44100,
-       [CIP_SFC_48000]  =  48000,
-       [CIP_SFC_88200]  =  88200,
-       [CIP_SFC_96000]  =  96000,
-       [CIP_SFC_176400] = 176400,
-       [CIP_SFC_192000] = 192000,
-};
-EXPORT_SYMBOL(amdtp_rate_table);
-
-/**
- * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
- * @s:         the AMDTP stream, which must be initialized.
- * @runtime:   the PCM substream runtime
- */
-int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
-                                       struct snd_pcm_runtime *runtime)
-{
-       int err;
-
-       /* AM824 in IEC 61883-6 can deliver 24bit data */
-       err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
-       if (err < 0)
-               goto end;
-
-       /*
-        * Currently firewire-lib processes 16 packets in one software
-        * interrupt callback. This equals to 2msec but actually the
-        * interval of the interrupts has a jitter.
-        * Additionally, even if adding a constraint to fit period size to
-        * 2msec, actual calculated frames per period doesn't equal to 2msec,
-        * depending on sampling rate.
-        * Anyway, the interval to call snd_pcm_period_elapsed() cannot 2msec.
-        * Here let us use 5msec for safe period interrupt.
-        */
-       err = snd_pcm_hw_constraint_minmax(runtime,
-                                          SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-                                          5000, UINT_MAX);
-       if (err < 0)
-               goto end;
-
-       /* Non-Blocking stream has no more constraints */
-       if (!(s->flags & CIP_BLOCKING))
-               goto end;
-
-       /*
-        * One AMDTP packet can include some frames. In blocking mode, the
-        * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
-        * depending on its sampling rate. For accurate period interrupt, it's
-        * preferrable to align period/buffer sizes to current SYT_INTERVAL.
-        *
-        * TODO: These constraints can be improved with proper rules.
-        * Currently apply LCM of SYT_INTERVALs.
-        */
-       err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
-       if (err < 0)
-               goto end;
-       err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
-end:
-       return err;
-}
-EXPORT_SYMBOL(amdtp_stream_add_pcm_hw_constraints);
-
-/**
- * amdtp_stream_set_parameters - set stream parameters
- * @s: the AMDTP stream to configure
- * @rate: the sample rate
- * @pcm_channels: the number of PCM samples in each data block, to be encoded
- *                as AM824 multi-bit linear audio
- * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
- *
- * The parameters must be set before the stream is started, and must not be
- * changed while the stream is running.
- */
-void amdtp_stream_set_parameters(struct amdtp_stream *s,
-                                unsigned int rate,
-                                unsigned int pcm_channels,
-                                unsigned int midi_ports)
-{
-       unsigned int i, sfc, midi_channels;
-
-       midi_channels = DIV_ROUND_UP(midi_ports, 8);
-
-       if (WARN_ON(amdtp_stream_running(s)) |
-           WARN_ON(pcm_channels > AMDTP_MAX_CHANNELS_FOR_PCM) |
-           WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI))
-               return;
-
-       for (sfc = 0; sfc < ARRAY_SIZE(amdtp_rate_table); ++sfc)
-               if (amdtp_rate_table[sfc] == rate)
-                       goto sfc_found;
-       WARN_ON(1);
-       return;
-
-sfc_found:
-       s->pcm_channels = pcm_channels;
-       s->sfc = sfc;
-       s->data_block_quadlets = s->pcm_channels + midi_channels;
-       s->midi_ports = midi_ports;
-
-       s->syt_interval = amdtp_syt_intervals[sfc];
-
-       /* default buffering in the device */
-       s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
-       if (s->flags & CIP_BLOCKING)
-               /* additional buffering needed to adjust for no-data packets */
-               s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
-
-       /* init the position map for PCM and MIDI channels */
-       for (i = 0; i < pcm_channels; i++)
-               s->pcm_positions[i] = i;
-       s->midi_position = s->pcm_channels;
-
-       /*
-        * We do not know the actual MIDI FIFO size of most devices.  Just
-        * assume two bytes, i.e., one byte can be received over the bus while
-        * the previous one is transmitted over MIDI.
-        * (The value here is adjusted for midi_ratelimit_per_packet().)
-        */
-       s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
-}
-EXPORT_SYMBOL(amdtp_stream_set_parameters);
-
-/**
- * amdtp_stream_get_max_payload - get the stream's packet size
- * @s: the AMDTP stream
- *
- * This function must not be called before the stream has been configured
- * with amdtp_stream_set_parameters().
- */
-unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
-{
-       unsigned int multiplier = 1;
-
-       if (s->flags & CIP_JUMBO_PAYLOAD)
-               multiplier = 5;
-
-       return 8 + s->syt_interval * s->data_block_quadlets * 4 * multiplier;
-}
-EXPORT_SYMBOL(amdtp_stream_get_max_payload);
-
-static void write_pcm_s16(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames);
-static void write_pcm_s32(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames);
-static void read_pcm_s32(struct amdtp_stream *s,
-                        struct snd_pcm_substream *pcm,
-                        __be32 *buffer, unsigned int frames);
-
-/**
- * amdtp_stream_set_pcm_format - set the PCM format
- * @s: the AMDTP stream to configure
- * @format: the format of the ALSA PCM device
- *
- * The sample format must be set after the other parameters (rate/PCM channels/
- * MIDI) and before the stream is started, and must not be changed while the
- * stream is running.
- */
-void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
-                                snd_pcm_format_t format)
-{
-       if (WARN_ON(amdtp_stream_pcm_running(s)))
-               return;
-
-       switch (format) {
-       default:
-               WARN_ON(1);
-               /* fall through */
-       case SNDRV_PCM_FORMAT_S16:
-               if (s->direction == AMDTP_OUT_STREAM) {
-                       s->transfer_samples = write_pcm_s16;
-                       break;
-               }
-               WARN_ON(1);
-               /* fall through */
-       case SNDRV_PCM_FORMAT_S32:
-               if (s->direction == AMDTP_OUT_STREAM)
-                       s->transfer_samples = write_pcm_s32;
-               else
-                       s->transfer_samples = read_pcm_s32;
-               break;
-       }
-}
-EXPORT_SYMBOL(amdtp_stream_set_pcm_format);
-
-/**
- * amdtp_stream_pcm_prepare - prepare PCM device for running
- * @s: the AMDTP stream
- *
- * This function should be called from the PCM device's .prepare callback.
- */
-void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
-{
-       tasklet_kill(&s->period_tasklet);
-       s->pcm_buffer_pointer = 0;
-       s->pcm_period_pointer = 0;
-       s->pointer_flush = true;
-}
-EXPORT_SYMBOL(amdtp_stream_pcm_prepare);
-
-static unsigned int calculate_data_blocks(struct amdtp_stream *s,
-                                         unsigned int syt)
-{
-       unsigned int phase, data_blocks;
-
-       /* Blocking mode. */
-       if (s->flags & CIP_BLOCKING) {
-               /* This module generate empty packet for 'no data'. */
-               if (syt == CIP_SYT_NO_INFO)
-                       data_blocks = 0;
-               else
-                       data_blocks = s->syt_interval;
-       /* Non-blocking mode. */
-       } else {
-               if (!cip_sfc_is_base_44100(s->sfc)) {
-                       /* Sample_rate / 8000 is an integer, and precomputed. */
-                       data_blocks = s->data_block_state;
-               } else {
-                       phase = s->data_block_state;
-
-               /*
-                * This calculates the number of data blocks per packet so that
-                * 1) the overall rate is correct and exactly synchronized to
-                *    the bus clock, and
-                * 2) packets with a rounded-up number of blocks occur as early
-                *    as possible in the sequence (to prevent underruns of the
-                *    device's buffer).
-                */
-                       if (s->sfc == CIP_SFC_44100)
-                               /* 6 6 5 6 5 6 5 ... */
-                               data_blocks = 5 + ((phase & 1) ^
-                                                  (phase == 0 || phase >= 40));
-                       else
-                               /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */
-                               data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
-                       if (++phase >= (80 >> (s->sfc >> 1)))
-                               phase = 0;
-                       s->data_block_state = phase;
-               }
-       }
-
-       return data_blocks;
-}
-
-static unsigned int calculate_syt(struct amdtp_stream *s,
-                                 unsigned int cycle)
-{
-       unsigned int syt_offset, phase, index, syt;
-
-       if (s->last_syt_offset < TICKS_PER_CYCLE) {
-               if (!cip_sfc_is_base_44100(s->sfc))
-                       syt_offset = s->last_syt_offset + s->syt_offset_state;
-               else {
-               /*
-                * The time, in ticks, of the n'th SYT_INTERVAL sample is:
-                *   n * SYT_INTERVAL * 24576000 / sample_rate
-                * Modulo TICKS_PER_CYCLE, the difference between successive
-                * elements is about 1386.23.  Rounding the results of this
-                * formula to the SYT precision results in a sequence of
-                * differences that begins with:
-                *   1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ...
-                * This code generates _exactly_ the same sequence.
-                */
-                       phase = s->syt_offset_state;
-                       index = phase % 13;
-                       syt_offset = s->last_syt_offset;
-                       syt_offset += 1386 + ((index && !(index & 3)) ||
-                                             phase == 146);
-                       if (++phase >= 147)
-                               phase = 0;
-                       s->syt_offset_state = phase;
-               }
-       } else
-               syt_offset = s->last_syt_offset - TICKS_PER_CYCLE;
-       s->last_syt_offset = syt_offset;
-
-       if (syt_offset < TICKS_PER_CYCLE) {
-               syt_offset += s->transfer_delay;
-               syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
-               syt += syt_offset % TICKS_PER_CYCLE;
-
-               return syt & CIP_SYT_MASK;
-       } else {
-               return CIP_SYT_NO_INFO;
-       }
-}
-
-static void write_pcm_s32(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       const u32 *src;
-
-       channels = s->pcm_channels;
-       src = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       buffer[s->pcm_positions[c]] =
-                                       cpu_to_be32((*src >> 8) | 0x40000000);
-                       src++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       src = (void *)runtime->dma_area;
-       }
-}
-
-static void write_pcm_s16(struct amdtp_stream *s,
-                         struct snd_pcm_substream *pcm,
-                         __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       const u16 *src;
-
-       channels = s->pcm_channels;
-       src = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       buffer[s->pcm_positions[c]] =
-                                       cpu_to_be32((*src << 8) | 0x42000000);
-                       src++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       src = (void *)runtime->dma_area;
-       }
-}
-
-static void read_pcm_s32(struct amdtp_stream *s,
-                        struct snd_pcm_substream *pcm,
-                        __be32 *buffer, unsigned int frames)
-{
-       struct snd_pcm_runtime *runtime = pcm->runtime;
-       unsigned int channels, remaining_frames, i, c;
-       u32 *dst;
-
-       channels = s->pcm_channels;
-       dst  = (void *)runtime->dma_area +
-                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
-       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < channels; ++c) {
-                       *dst = be32_to_cpu(buffer[s->pcm_positions[c]]) << 8;
-                       dst++;
-               }
-               buffer += s->data_block_quadlets;
-               if (--remaining_frames == 0)
-                       dst = (void *)runtime->dma_area;
-       }
-}
-
-static void write_pcm_silence(struct amdtp_stream *s,
-                             __be32 *buffer, unsigned int frames)
-{
-       unsigned int i, c;
-
-       for (i = 0; i < frames; ++i) {
-               for (c = 0; c < s->pcm_channels; ++c)
-                       buffer[s->pcm_positions[c]] = cpu_to_be32(0x40000000);
-               buffer += s->data_block_quadlets;
-       }
-}
-
-/*
- * To avoid sending MIDI bytes at too high a rate, assume that the receiving
- * device has a FIFO, and track how much it is filled.  This values increases
- * by one whenever we send one byte in a packet, but the FIFO empties at
- * a constant rate independent of our packet rate.  One packet has syt_interval
- * samples, so the number of bytes that empty out of the FIFO, per packet(!),
- * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
- * fractional values, the values in midi_fifo_used[] are measured in bytes
- * multiplied by the sample rate.
- */
-static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
-{
-       int used;
-
-       used = s->midi_fifo_used[port];
-       if (used == 0) /* common shortcut */
-               return true;
-
-       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
-       used = max(used, 0);
-       s->midi_fifo_used[port] = used;
-
-       return used < s->midi_fifo_limit;
-}
-
-static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
-{
-       s->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
-}
-
-static void write_midi_messages(struct amdtp_stream *s,
-                               __be32 *buffer, unsigned int frames)
-{
-       unsigned int f, port;
-       u8 *b;
-
-       for (f = 0; f < frames; f++) {
-               b = (u8 *)&buffer[s->midi_position];
-
-               port = (s->data_block_counter + f) % 8;
-               if (f < MAX_MIDI_RX_BLOCKS &&
-                   midi_ratelimit_per_packet(s, port) &&
-                   s->midi[port] != NULL &&
-                   snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) {
-                       midi_rate_use_one_byte(s, port);
-                       b[0] = 0x81;
-               } else {
-                       b[0] = 0x80;
-                       b[1] = 0;
-               }
-               b[2] = 0;
-               b[3] = 0;
-
-               buffer += s->data_block_quadlets;
-       }
-}
-
-static void read_midi_messages(struct amdtp_stream *s,
-                              __be32 *buffer, unsigned int frames)
-{
-       unsigned int f, port;
-       int len;
-       u8 *b;
-
-       for (f = 0; f < frames; f++) {
-               port = (s->data_block_counter + f) % 8;
-               b = (u8 *)&buffer[s->midi_position];
-
-               len = b[0] - 0x80;
-               if ((1 <= len) &&  (len <= 3) && (s->midi[port]))
-                       snd_rawmidi_receive(s->midi[port], b + 1, len);
-
-               buffer += s->data_block_quadlets;
-       }
-}
-
-static void update_pcm_pointers(struct amdtp_stream *s,
-                               struct snd_pcm_substream *pcm,
-                               unsigned int frames)
-{
-       unsigned int ptr;
-
-       /*
-        * In IEC 61883-6, one data block represents one event. In ALSA, one
-        * event equals to one PCM frame. But Dice has a quirk to transfer
-        * two PCM frames in one data block.
-        */
-       if (s->double_pcm_frames)
-               frames *= 2;
-
-       ptr = s->pcm_buffer_pointer + frames;
-       if (ptr >= pcm->runtime->buffer_size)
-               ptr -= pcm->runtime->buffer_size;
-       ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
-
-       s->pcm_period_pointer += frames;
-       if (s->pcm_period_pointer >= pcm->runtime->period_size) {
-               s->pcm_period_pointer -= pcm->runtime->period_size;
-               s->pointer_flush = false;
-               tasklet_hi_schedule(&s->period_tasklet);
-       }
-}
-
-static void pcm_period_tasklet(unsigned long data)
-{
-       struct amdtp_stream *s = (void *)data;
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
-
-       if (pcm)
-               snd_pcm_period_elapsed(pcm);
-}
-
-static int queue_packet(struct amdtp_stream *s,
-                       unsigned int header_length,
-                       unsigned int payload_length, bool skip)
-{
-       struct fw_iso_packet p = {0};
-       int err = 0;
-
-       if (IS_ERR(s->context))
-               goto end;
-
-       p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL);
-       p.tag = TAG_CIP;
-       p.header_length = header_length;
-       p.payload_length = (!skip) ? payload_length : 0;
-       p.skip = skip;
-       err = fw_iso_context_queue(s->context, &p, &s->buffer.iso_buffer,
-                                  s->buffer.packets[s->packet_index].offset);
-       if (err < 0) {
-               dev_err(&s->unit->device, "queueing error: %d\n", err);
-               goto end;
-       }
-
-       if (++s->packet_index >= QUEUE_LENGTH)
-               s->packet_index = 0;
-end:
-       return err;
-}
-
-static inline int queue_out_packet(struct amdtp_stream *s,
-                                  unsigned int payload_length, bool skip)
-{
-       return queue_packet(s, OUT_PACKET_HEADER_SIZE,
-                           payload_length, skip);
-}
-
-static inline int queue_in_packet(struct amdtp_stream *s)
-{
-       return queue_packet(s, IN_PACKET_HEADER_SIZE,
-                           amdtp_stream_get_max_payload(s), false);
-}
-
-static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
-                            unsigned int syt)
-{
-       __be32 *buffer;
-       unsigned int payload_length;
-       struct snd_pcm_substream *pcm;
-
-       buffer = s->buffer.packets[s->packet_index].buffer;
-       buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
-                               (s->data_block_quadlets << CIP_DBS_SHIFT) |
-                               s->data_block_counter);
-       buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 |
-                               (s->sfc << CIP_FDF_SHIFT) | syt);
-       buffer += 2;
-
-       pcm = ACCESS_ONCE(s->pcm);
-       if (pcm)
-               s->transfer_samples(s, pcm, buffer, data_blocks);
-       else
-               write_pcm_silence(s, buffer, data_blocks);
-       if (s->midi_ports)
-               write_midi_messages(s, buffer, data_blocks);
-
-       s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
-
-       payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
-       if (queue_out_packet(s, payload_length, false) < 0)
-               return -EIO;
-
-       if (pcm)
-               update_pcm_pointers(s, pcm, data_blocks);
-
-       /* No need to return the number of handled data blocks. */
-       return 0;
-}
-
-static int handle_in_packet(struct amdtp_stream *s,
-                           unsigned int payload_quadlets, __be32 *buffer,
-                           unsigned int *data_blocks)
-{
-       u32 cip_header[2];
-       unsigned int data_block_quadlets, data_block_counter, dbc_interval;
-       struct snd_pcm_substream *pcm = NULL;
-       bool lost;
-
-       cip_header[0] = be32_to_cpu(buffer[0]);
-       cip_header[1] = be32_to_cpu(buffer[1]);
-
-       /*
-        * This module supports 'Two-quadlet CIP header with SYT field'.
-        * For convenience, also check FMT field is AM824 or not.
-        */
-       if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
-           ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH) ||
-           ((cip_header[1] & CIP_FMT_MASK) != CIP_FMT_AM)) {
-               dev_info_ratelimited(&s->unit->device,
-                               "Invalid CIP header for AMDTP: %08X:%08X\n",
-                               cip_header[0], cip_header[1]);
-               *data_blocks = 0;
-               goto end;
-       }
-
-       /* Calculate data blocks */
-       if (payload_quadlets < 3 ||
-           ((cip_header[1] & CIP_FDF_MASK) ==
-                               (AMDTP_FDF_NO_DATA << CIP_FDF_SHIFT))) {
-               *data_blocks = 0;
-       } else {
-               data_block_quadlets =
-                       (cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
-               /* avoid division by zero */
-               if (data_block_quadlets == 0) {
-                       dev_err(&s->unit->device,
-                               "Detect invalid value in dbs field: %08X\n",
-                               cip_header[0]);
-                       return -EPROTO;
-               }
-               if (s->flags & CIP_WRONG_DBS)
-                       data_block_quadlets = s->data_block_quadlets;
-
-               *data_blocks = (payload_quadlets - 2) / data_block_quadlets;
-       }
-
-       /* Check data block counter continuity */
-       data_block_counter = cip_header[0] & CIP_DBC_MASK;
-       if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
-           s->data_block_counter != UINT_MAX)
-               data_block_counter = s->data_block_counter;
-
-       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
-            data_block_counter == s->tx_first_dbc) ||
-           s->data_block_counter == UINT_MAX) {
-               lost = false;
-       } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
-               lost = data_block_counter != s->data_block_counter;
-       } else {
-               if ((*data_blocks > 0) && (s->tx_dbc_interval > 0))
-                       dbc_interval = s->tx_dbc_interval;
-               else
-                       dbc_interval = *data_blocks;
-
-               lost = data_block_counter !=
-                      ((s->data_block_counter + dbc_interval) & 0xff);
-       }
-
-       if (lost) {
-               dev_err(&s->unit->device,
-                       "Detect discontinuity of CIP: %02X %02X\n",
-                       s->data_block_counter, data_block_counter);
-               return -EIO;
-       }
-
-       if (*data_blocks > 0) {
-               buffer += 2;
-
-               pcm = ACCESS_ONCE(s->pcm);
-               if (pcm)
-                       s->transfer_samples(s, pcm, buffer, *data_blocks);
-
-               if (s->midi_ports)
-                       read_midi_messages(s, buffer, *data_blocks);
-       }
-
-       if (s->flags & CIP_DBC_IS_END_EVENT)
-               s->data_block_counter = data_block_counter;
-       else
-               s->data_block_counter =
-                               (data_block_counter + *data_blocks) & 0xff;
-end:
-       if (queue_in_packet(s) < 0)
-               return -EIO;
-
-       if (pcm)
-               update_pcm_pointers(s, pcm, *data_blocks);
-
-       return 0;
-}
-
-static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
-                               size_t header_length, void *header,
-                               void *private_data)
-{
-       struct amdtp_stream *s = private_data;
-       unsigned int i, syt, packets = header_length / 4;
-       unsigned int data_blocks;
-
-       if (s->packet_index < 0)
-               return;
-
-       /*
-        * Compute the cycle of the last queued packet.
-        * (We need only the four lowest bits for the SYT, so we can ignore
-        * that bits 0-11 must wrap around at 3072.)
-        */
-       cycle += QUEUE_LENGTH - packets;
-
-       for (i = 0; i < packets; ++i) {
-               syt = calculate_syt(s, ++cycle);
-               data_blocks = calculate_data_blocks(s, syt);
-
-               if (handle_out_packet(s, data_blocks, syt) < 0) {
-                       s->packet_index = -1;
-                       amdtp_stream_pcm_abort(s);
-                       return;
-               }
-       }
-
-       fw_iso_context_queue_flush(s->context);
-}
-
-static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
-                              size_t header_length, void *header,
-                              void *private_data)
-{
-       struct amdtp_stream *s = private_data;
-       unsigned int p, syt, packets;
-       unsigned int payload_quadlets, max_payload_quadlets;
-       unsigned int data_blocks;
-       __be32 *buffer, *headers = header;
-
-       if (s->packet_index < 0)
-               return;
-
-       /* The number of packets in buffer */
-       packets = header_length / IN_PACKET_HEADER_SIZE;
-
-       /* For buffer-over-run prevention. */
-       max_payload_quadlets = amdtp_stream_get_max_payload(s) / 4;
-
-       for (p = 0; p < packets; p++) {
-               buffer = s->buffer.packets[s->packet_index].buffer;
-
-               /* The number of quadlets in this packet */
-               payload_quadlets =
-                       (be32_to_cpu(headers[p]) >> ISO_DATA_LENGTH_SHIFT) / 4;
-               if (payload_quadlets > max_payload_quadlets) {
-                       dev_err(&s->unit->device,
-                               "Detect jumbo payload: %02x %02x\n",
-                               payload_quadlets, max_payload_quadlets);
-                       s->packet_index = -1;
-                       break;
-               }
-
-               if (handle_in_packet(s, payload_quadlets, buffer,
-                                                       &data_blocks) < 0) {
-                       s->packet_index = -1;
-                       break;
-               }
-
-               /* Process sync slave stream */
-               if (s->sync_slave && s->sync_slave->callbacked) {
-                       syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
-                       if (handle_out_packet(s->sync_slave,
-                                             data_blocks, syt) < 0) {
-                               s->packet_index = -1;
-                               break;
-                       }
-               }
-       }
-
-       /* Queueing error or detecting discontinuity */
-       if (s->packet_index < 0) {
-               amdtp_stream_pcm_abort(s);
-
-               /* Abort sync slave. */
-               if (s->sync_slave) {
-                       s->sync_slave->packet_index = -1;
-                       amdtp_stream_pcm_abort(s->sync_slave);
-               }
-               return;
-       }
-
-       /* when sync to device, flush the packets for slave stream */
-       if (s->sync_slave && s->sync_slave->callbacked)
-               fw_iso_context_queue_flush(s->sync_slave->context);
-
-       fw_iso_context_queue_flush(s->context);
-}
-
-/* processing is done by master callback */
-static void slave_stream_callback(struct fw_iso_context *context, u32 cycle,
-                                 size_t header_length, void *header,
-                                 void *private_data)
-{
-       return;
-}
-
-/* this is executed one time */
-static void amdtp_stream_first_callback(struct fw_iso_context *context,
-                                       u32 cycle, size_t header_length,
-                                       void *header, void *private_data)
-{
-       struct amdtp_stream *s = private_data;
-
-       /*
-        * For in-stream, first packet has come.
-        * For out-stream, prepared to transmit first packet
-        */
-       s->callbacked = true;
-       wake_up(&s->callback_wait);
-
-       if (s->direction == AMDTP_IN_STREAM)
-               context->callback.sc = in_stream_callback;
-       else if (s->flags & CIP_SYNC_TO_DEVICE)
-               context->callback.sc = slave_stream_callback;
-       else
-               context->callback.sc = out_stream_callback;
-
-       context->callback.sc(context, cycle, header_length, header, s);
-}
-
-/**
- * amdtp_stream_start - start transferring packets
- * @s: the AMDTP stream to start
- * @channel: the isochronous channel on the bus
- * @speed: firewire speed code
- *
- * The stream cannot be started until it has been configured with
- * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
- * device can be started.
- */
-int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
-{
-       static const struct {
-               unsigned int data_block;
-               unsigned int syt_offset;
-       } initial_state[] = {
-               [CIP_SFC_32000]  = {  4, 3072 },
-               [CIP_SFC_48000]  = {  6, 1024 },
-               [CIP_SFC_96000]  = { 12, 1024 },
-               [CIP_SFC_192000] = { 24, 1024 },
-               [CIP_SFC_44100]  = {  0,   67 },
-               [CIP_SFC_88200]  = {  0,   67 },
-               [CIP_SFC_176400] = {  0,   67 },
-       };
-       unsigned int header_size;
-       enum dma_data_direction dir;
-       int type, tag, err;
-
-       mutex_lock(&s->mutex);
-
-       if (WARN_ON(amdtp_stream_running(s) ||
-                   (s->data_block_quadlets < 1))) {
-               err = -EBADFD;
-               goto err_unlock;
-       }
-
-       if (s->direction == AMDTP_IN_STREAM &&
-           s->flags & CIP_SKIP_INIT_DBC_CHECK)
-               s->data_block_counter = UINT_MAX;
-       else
-               s->data_block_counter = 0;
-       s->data_block_state = initial_state[s->sfc].data_block;
-       s->syt_offset_state = initial_state[s->sfc].syt_offset;
-       s->last_syt_offset = TICKS_PER_CYCLE;
-
-       /* initialize packet buffer */
-       if (s->direction == AMDTP_IN_STREAM) {
-               dir = DMA_FROM_DEVICE;
-               type = FW_ISO_CONTEXT_RECEIVE;
-               header_size = IN_PACKET_HEADER_SIZE;
-       } else {
-               dir = DMA_TO_DEVICE;
-               type = FW_ISO_CONTEXT_TRANSMIT;
-               header_size = OUT_PACKET_HEADER_SIZE;
-       }
-       err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
-                                     amdtp_stream_get_max_payload(s), dir);
-       if (err < 0)
-               goto err_unlock;
-
-       s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
-                                          type, channel, speed, header_size,
-                                          amdtp_stream_first_callback, s);
-       if (IS_ERR(s->context)) {
-               err = PTR_ERR(s->context);
-               if (err == -EBUSY)
-                       dev_err(&s->unit->device,
-                               "no free stream on this controller\n");
-               goto err_buffer;
-       }
-
-       amdtp_stream_update(s);
-
-       s->packet_index = 0;
-       do {
-               if (s->direction == AMDTP_IN_STREAM)
-                       err = queue_in_packet(s);
-               else
-                       err = queue_out_packet(s, 0, true);
-               if (err < 0)
-                       goto err_context;
-       } while (s->packet_index > 0);
-
-       /* NOTE: TAG1 matches CIP. This just affects in stream. */
-       tag = FW_ISO_CONTEXT_MATCH_TAG1;
-       if (s->flags & CIP_EMPTY_WITH_TAG0)
-               tag |= FW_ISO_CONTEXT_MATCH_TAG0;
-
-       s->callbacked = false;
-       err = fw_iso_context_start(s->context, -1, 0, tag);
-       if (err < 0)
-               goto err_context;
-
-       mutex_unlock(&s->mutex);
-
-       return 0;
-
-err_context:
-       fw_iso_context_destroy(s->context);
-       s->context = ERR_PTR(-1);
-err_buffer:
-       iso_packets_buffer_destroy(&s->buffer, s->unit);
-err_unlock:
-       mutex_unlock(&s->mutex);
-
-       return err;
-}
-EXPORT_SYMBOL(amdtp_stream_start);
-
-/**
- * amdtp_stream_pcm_pointer - get the PCM buffer position
- * @s: the AMDTP stream that transports the PCM data
- *
- * Returns the current buffer position, in frames.
- */
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
-{
-       /* this optimization is allowed to be racy */
-       if (s->pointer_flush && amdtp_stream_running(s))
-               fw_iso_context_flush_completions(s->context);
-       else
-               s->pointer_flush = true;
-
-       return ACCESS_ONCE(s->pcm_buffer_pointer);
-}
-EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
-
-/**
- * amdtp_stream_update - update the stream after a bus reset
- * @s: the AMDTP stream
- */
-void amdtp_stream_update(struct amdtp_stream *s)
-{
-       /* Precomputing. */
-       ACCESS_ONCE(s->source_node_id_field) =
-               (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) &
-                                                               CIP_SID_MASK;
-}
-EXPORT_SYMBOL(amdtp_stream_update);
-
-/**
- * amdtp_stream_stop - stop sending packets
- * @s: the AMDTP stream to stop
- *
- * All PCM and MIDI devices of the stream must be stopped before the stream
- * itself can be stopped.
- */
-void amdtp_stream_stop(struct amdtp_stream *s)
-{
-       mutex_lock(&s->mutex);
-
-       if (!amdtp_stream_running(s)) {
-               mutex_unlock(&s->mutex);
-               return;
-       }
-
-       tasklet_kill(&s->period_tasklet);
-       fw_iso_context_stop(s->context);
-       fw_iso_context_destroy(s->context);
-       s->context = ERR_PTR(-1);
-       iso_packets_buffer_destroy(&s->buffer, s->unit);
-
-       s->callbacked = false;
-
-       mutex_unlock(&s->mutex);
-}
-EXPORT_SYMBOL(amdtp_stream_stop);
-
-/**
- * amdtp_stream_pcm_abort - abort the running PCM device
- * @s: the AMDTP stream about to be stopped
- *
- * If the isochronous stream needs to be stopped asynchronously, call this
- * function first to stop the PCM device.
- */
-void amdtp_stream_pcm_abort(struct amdtp_stream *s)
-{
-       struct snd_pcm_substream *pcm;
-
-       pcm = ACCESS_ONCE(s->pcm);
-       if (pcm)
-               snd_pcm_stop_xrun(pcm);
-}
-EXPORT_SYMBOL(amdtp_stream_pcm_abort);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
deleted file mode 100644 (file)
index b2cf9e7..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
-#define SOUND_FIREWIRE_AMDTP_H_INCLUDED
-
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <sound/asound.h>
-#include "packets-buffer.h"
-
-/**
- * enum cip_flags - describes details of the streaming protocol
- * @CIP_NONBLOCKING: In non-blocking mode, each packet contains
- *     sample_rate/8000 samples, with rounding up or down to adjust
- *     for clock skew and left-over fractional samples.  This should
- *     be used if supported by the device.
- * @CIP_BLOCKING: In blocking mode, each packet contains either zero or
- *     SYT_INTERVAL samples, with these two types alternating so that
- *     the overall sample rate comes out right.
- * @CIP_SYNC_TO_DEVICE: In sync to device mode, time stamp in out packets is
- *     generated by in packets. Defaultly this driver generates timestamp.
- * @CIP_EMPTY_WITH_TAG0: Only for in-stream. Empty in-packets have TAG0.
- * @CIP_DBC_IS_END_EVENT: Only for in-stream. The value of dbc in an in-packet
- *     corresponds to the end of event in the packet. Out of IEC 61883.
- * @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets.
- *     The value of data_block_quadlets is used instead of reported value.
- * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream.  Packets with zero in dbc is
- *     skipped for detecting discontinuity.
- * @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first
- *     packet is not continuous from an initial value.
- * @CIP_EMPTY_HAS_WRONG_DBC: Only for in-stream. The value of dbc in empty
- *     packet is wrong but the others are correct.
- * @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an
- *     packet is larger than IEC 61883-6 defines. Current implementation
- *     allows 5 times as large as IEC 61883-6 defines.
- */
-enum cip_flags {
-       CIP_NONBLOCKING         = 0x00,
-       CIP_BLOCKING            = 0x01,
-       CIP_SYNC_TO_DEVICE      = 0x02,
-       CIP_EMPTY_WITH_TAG0     = 0x04,
-       CIP_DBC_IS_END_EVENT    = 0x08,
-       CIP_WRONG_DBS           = 0x10,
-       CIP_SKIP_DBC_ZERO_CHECK = 0x20,
-       CIP_SKIP_INIT_DBC_CHECK = 0x40,
-       CIP_EMPTY_HAS_WRONG_DBC = 0x80,
-       CIP_JUMBO_PAYLOAD       = 0x100,
-};
-
-/**
- * enum cip_sfc - supported Sampling Frequency Codes (SFCs)
- * @CIP_SFC_32000:   32,000 data blocks
- * @CIP_SFC_44100:   44,100 data blocks
- * @CIP_SFC_48000:   48,000 data blocks
- * @CIP_SFC_88200:   88,200 data blocks
- * @CIP_SFC_96000:   96,000 data blocks
- * @CIP_SFC_176400: 176,400 data blocks
- * @CIP_SFC_192000: 192,000 data blocks
- * @CIP_SFC_COUNT: the number of supported SFCs
- *
- * These values are used to show nominal Sampling Frequency Code in
- * Format Dependent Field (FDF) of AMDTP packet header. In IEC 61883-6:2002,
- * this code means the number of events per second. Actually the code
- * represents the number of data blocks transferred per second in an AMDTP
- * stream.
- *
- * In IEC 61883-6:2005, some extensions were added to support more types of
- * data such as 'One Bit LInear Audio', therefore the meaning of SFC became
- * different depending on the types.
- *
- * Currently our implementation is compatible with IEC 61883-6:2002.
- */
-enum cip_sfc {
-       CIP_SFC_32000  = 0,
-       CIP_SFC_44100  = 1,
-       CIP_SFC_48000  = 2,
-       CIP_SFC_88200  = 3,
-       CIP_SFC_96000  = 4,
-       CIP_SFC_176400 = 5,
-       CIP_SFC_192000 = 6,
-       CIP_SFC_COUNT
-};
-
-#define AMDTP_IN_PCM_FORMAT_BITS       SNDRV_PCM_FMTBIT_S32
-
-#define AMDTP_OUT_PCM_FORMAT_BITS      (SNDRV_PCM_FMTBIT_S16 | \
-                                        SNDRV_PCM_FMTBIT_S32)
-
-
-/*
- * This module supports maximum 64 PCM channels for one PCM stream
- * This is for our convenience.
- */
-#define AMDTP_MAX_CHANNELS_FOR_PCM     64
-
-/*
- * AMDTP packet can include channels for MIDI conformant data.
- * Each MIDI conformant data channel includes 8 MPX-MIDI data stream.
- * Each MPX-MIDI data stream includes one data stream from/to MIDI ports.
- *
- * This module supports maximum 1 MIDI conformant data channels.
- * Then this AMDTP packets can transfer maximum 8 MIDI data streams.
- */
-#define AMDTP_MAX_CHANNELS_FOR_MIDI    1
-
-struct fw_unit;
-struct fw_iso_context;
-struct snd_pcm_substream;
-struct snd_pcm_runtime;
-struct snd_rawmidi_substream;
-
-enum amdtp_stream_direction {
-       AMDTP_OUT_STREAM = 0,
-       AMDTP_IN_STREAM
-};
-
-struct amdtp_stream {
-       struct fw_unit *unit;
-       enum cip_flags flags;
-       enum amdtp_stream_direction direction;
-       struct fw_iso_context *context;
-       struct mutex mutex;
-
-       enum cip_sfc sfc;
-       unsigned int data_block_quadlets;
-       unsigned int pcm_channels;
-       unsigned int midi_ports;
-       void (*transfer_samples)(struct amdtp_stream *s,
-                                struct snd_pcm_substream *pcm,
-                                __be32 *buffer, unsigned int frames);
-       u8 pcm_positions[AMDTP_MAX_CHANNELS_FOR_PCM];
-       u8 midi_position;
-
-       unsigned int syt_interval;
-       unsigned int transfer_delay;
-       unsigned int source_node_id_field;
-       struct iso_packets_buffer buffer;
-
-       struct snd_pcm_substream *pcm;
-       struct tasklet_struct period_tasklet;
-
-       int packet_index;
-       unsigned int data_block_counter;
-
-       unsigned int data_block_state;
-
-       unsigned int last_syt_offset;
-       unsigned int syt_offset_state;
-
-       unsigned int pcm_buffer_pointer;
-       unsigned int pcm_period_pointer;
-       bool pointer_flush;
-       bool double_pcm_frames;
-
-       struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
-       int midi_fifo_limit;
-       int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
-
-       /* quirk: fixed interval of dbc between previos/current packets. */
-       unsigned int tx_dbc_interval;
-       /* quirk: indicate the value of dbc field in a first packet. */
-       unsigned int tx_first_dbc;
-
-       bool callbacked;
-       wait_queue_head_t callback_wait;
-       struct amdtp_stream *sync_slave;
-};
-
-int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
-                     enum amdtp_stream_direction dir,
-                     enum cip_flags flags);
-void amdtp_stream_destroy(struct amdtp_stream *s);
-
-void amdtp_stream_set_parameters(struct amdtp_stream *s,
-                                unsigned int rate,
-                                unsigned int pcm_channels,
-                                unsigned int midi_ports);
-unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
-
-int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed);
-void amdtp_stream_update(struct amdtp_stream *s);
-void amdtp_stream_stop(struct amdtp_stream *s);
-
-int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
-                                       struct snd_pcm_runtime *runtime);
-void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
-                                snd_pcm_format_t format);
-void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
-void amdtp_stream_pcm_abort(struct amdtp_stream *s);
-
-extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
-extern const unsigned int amdtp_rate_table[CIP_SFC_COUNT];
-
-/**
- * amdtp_stream_running - check stream is running or not
- * @s: the AMDTP stream
- *
- * If this function returns true, the stream is running.
- */
-static inline bool amdtp_stream_running(struct amdtp_stream *s)
-{
-       return !IS_ERR(s->context);
-}
-
-/**
- * amdtp_streaming_error - check for streaming error
- * @s: the AMDTP stream
- *
- * If this function returns true, the stream's packet queue has stopped due to
- * an asynchronous error.
- */
-static inline bool amdtp_streaming_error(struct amdtp_stream *s)
-{
-       return s->packet_index < 0;
-}
-
-/**
- * amdtp_stream_pcm_running - check PCM substream is running or not
- * @s: the AMDTP stream
- *
- * If this function returns true, PCM substream in the AMDTP stream is running.
- */
-static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s)
-{
-       return !!s->pcm;
-}
-
-/**
- * amdtp_stream_pcm_trigger - start/stop playback from a PCM device
- * @s: the AMDTP stream
- * @pcm: the PCM device to be started, or %NULL to stop the current device
- *
- * Call this function on a running isochronous stream to enable the actual
- * transmission of PCM data.  This function should be called from the PCM
- * device's .trigger callback.
- */
-static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s,
-                                           struct snd_pcm_substream *pcm)
-{
-       ACCESS_ONCE(s->pcm) = pcm;
-}
-
-/**
- * amdtp_stream_midi_trigger - start/stop playback/capture with a MIDI device
- * @s: the AMDTP stream
- * @port: index of MIDI port
- * @midi: the MIDI device to be started, or %NULL to stop the current device
- *
- * Call this function on a running isochronous stream to enable the actual
- * transmission of MIDI data.  This function should be called from the MIDI
- * device's .trigger callback.
- */
-static inline void amdtp_stream_midi_trigger(struct amdtp_stream *s,
-                                            unsigned int port,
-                                            struct snd_rawmidi_substream *midi)
-{
-       if (port < s->midi_ports)
-               ACCESS_ONCE(s->midi[port]) = midi;
-}
-
-static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
-{
-       return sfc & 1;
-}
-
-static inline void amdtp_stream_set_sync(enum cip_flags sync_mode,
-                                        struct amdtp_stream *master,
-                                        struct amdtp_stream *slave)
-{
-       if (sync_mode == CIP_SYNC_TO_DEVICE) {
-               master->flags |= CIP_SYNC_TO_DEVICE;
-               slave->flags |= CIP_SYNC_TO_DEVICE;
-               master->sync_slave = slave;
-       } else {
-               master->flags &= ~CIP_SYNC_TO_DEVICE;
-               slave->flags &= ~CIP_SYNC_TO_DEVICE;
-               master->sync_slave = NULL;
-       }
-
-       slave->sync_slave = NULL;
-}
-
-/**
- * amdtp_stream_wait_callback - sleep till callbacked or timeout
- * @s: the AMDTP stream
- * @timeout: msec till timeout
- *
- * If this function return false, the AMDTP stream should be stopped.
- */
-static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
-                                             unsigned int timeout)
-{
-       return wait_event_timeout(s->callback_wait,
-                                 s->callbacked == true,
-                                 msecs_to_jiffies(timeout)) > 0;
-}
-
-#endif
index 6cf470c80d1fd1e37f92b65d933838da405524cd..af7ed66432661d307cded6269f9072d17ee99b35 100644 (file)
@@ -1,4 +1,4 @@
 snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
                  bebob_pcm.o bebob_hwdep.o bebob_terratec.o bebob_yamaha.o \
                  bebob_focusrite.o bebob_maudio.o bebob.o
-obj-m += snd-bebob.o
+obj-$(CONFIG_SND_BEBOB) += snd-bebob.o
index 27a04ac8ffee938fc5e1cd023f6472c3f57f8c2e..091290d1f3ea0a99b8a6d81d501a385863efe64d 100644 (file)
@@ -41,7 +41,8 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
 #define VEN_EDIROL     0x000040ab
 #define VEN_PRESONUS   0x00000a92
 #define VEN_BRIDGECO   0x000007f5
-#define VEN_MACKIE     0x0000000f
+#define VEN_MACKIE1    0x0000000f
+#define VEN_MACKIE2    0x00000ff2
 #define VEN_STANTON    0x00001260
 #define VEN_TASCAM     0x0000022e
 #define VEN_BEHRINGER  0x00001564
@@ -334,7 +335,7 @@ static void bebob_remove(struct fw_unit *unit)
        snd_card_free_when_closed(bebob->card);
 }
 
-static struct snd_bebob_rate_spec normal_rate_spec = {
+static const struct snd_bebob_rate_spec normal_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate
 };
@@ -360,9 +361,9 @@ static const struct ieee1394_device_id bebob_id_table[] = {
        /* BridgeCo, Audio5 */
        SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
        /* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
-       SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
+       SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal),
        /* Mackie, d.2 (Firewire Option) */
-       SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
+       SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal),
        /* Stanton, ScratchAmp */
        SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
        /* Tascam, IF-FW DM */
index d23caca7f369076fe5f9bd7c76c01f5c76e259ab..4d8fcc78e747cb5d4232ed9f76c3662a242d72d3 100644 (file)
@@ -31,7 +31,7 @@
 #include "../fcp.h"
 #include "../packets-buffer.h"
 #include "../iso-resources.h"
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../cmp.h"
 
 /* basic register addresses on DM1000/DM1100/DM1500 */
@@ -70,9 +70,9 @@ struct snd_bebob_meter_spec {
        int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size);
 };
 struct snd_bebob_spec {
-       struct snd_bebob_clock_spec *clock;
-       struct snd_bebob_rate_spec *rate;
-       struct snd_bebob_meter_spec *meter;
+       const struct snd_bebob_clock_spec *clock;
+       const struct snd_bebob_rate_spec *rate;
+       const struct snd_bebob_meter_spec *meter;
 };
 
 struct snd_bebob {
@@ -235,19 +235,19 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob);
 int snd_bebob_create_hwdep_device(struct snd_bebob *bebob);
 
 /* model specific operations */
-extern struct snd_bebob_spec phase88_rack_spec;
-extern struct snd_bebob_spec phase24_series_spec;
-extern struct snd_bebob_spec yamaha_go_spec;
-extern struct snd_bebob_spec saffirepro_26_spec;
-extern struct snd_bebob_spec saffirepro_10_spec;
-extern struct snd_bebob_spec saffire_le_spec;
-extern struct snd_bebob_spec saffire_spec;
-extern struct snd_bebob_spec maudio_fw410_spec;
-extern struct snd_bebob_spec maudio_audiophile_spec;
-extern struct snd_bebob_spec maudio_solo_spec;
-extern struct snd_bebob_spec maudio_ozonic_spec;
-extern struct snd_bebob_spec maudio_nrv10_spec;
-extern struct snd_bebob_spec maudio_special_spec;
+extern const struct snd_bebob_spec phase88_rack_spec;
+extern const struct snd_bebob_spec phase24_series_spec;
+extern const struct snd_bebob_spec yamaha_go_spec;
+extern const struct snd_bebob_spec saffirepro_26_spec;
+extern const struct snd_bebob_spec saffirepro_10_spec;
+extern const struct snd_bebob_spec saffire_le_spec;
+extern const struct snd_bebob_spec saffire_spec;
+extern const struct snd_bebob_spec maudio_fw410_spec;
+extern const struct snd_bebob_spec maudio_audiophile_spec;
+extern const struct snd_bebob_spec maudio_solo_spec;
+extern const struct snd_bebob_spec maudio_ozonic_spec;
+extern const struct snd_bebob_spec maudio_nrv10_spec;
+extern const struct snd_bebob_spec maudio_special_spec;
 int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
 int snd_bebob_maudio_load_firmware(struct fw_unit *unit);
 
index a1a39494ea6c9bb985815f9ef18f799dd7b0062f..f1109005794944cd759b90ede92a6fc601ab251e 100644 (file)
@@ -200,7 +200,7 @@ end:
        return err;
 }
 
-struct snd_bebob_spec saffire_le_spec;
+const struct snd_bebob_spec saffire_le_spec;
 static enum snd_bebob_clock_type saffire_both_clk_src_types[] = {
        SND_BEBOB_CLOCK_TYPE_INTERNAL,
        SND_BEBOB_CLOCK_TYPE_EXTERNAL,
@@ -229,7 +229,7 @@ static const char *const saffire_meter_labels[] = {
 static int
 saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
 {
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        unsigned int channels;
        u64 offset;
        int err;
@@ -260,60 +260,60 @@ saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
        return err;
 }
 
-static struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
+static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
        .get    = &saffirepro_both_clk_freq_get,
        .set    = &saffirepro_both_clk_freq_set,
 };
 /* Saffire Pro 26 I/O  */
-static struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
+static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
        .num    = ARRAY_SIZE(saffirepro_26_clk_src_types),
        .types  = saffirepro_26_clk_src_types,
        .get    = &saffirepro_both_clk_src_get,
 };
-struct snd_bebob_spec saffirepro_26_spec = {
+const struct snd_bebob_spec saffirepro_26_spec = {
        .clock  = &saffirepro_26_clk_spec,
        .rate   = &saffirepro_both_rate_spec,
        .meter  = NULL
 };
 /* Saffire Pro 10 I/O */
-static struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
+static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
        .num    = ARRAY_SIZE(saffirepro_10_clk_src_types),
        .types  = saffirepro_10_clk_src_types,
        .get    = &saffirepro_both_clk_src_get,
 };
-struct snd_bebob_spec saffirepro_10_spec = {
+const struct snd_bebob_spec saffirepro_10_spec = {
        .clock  = &saffirepro_10_clk_spec,
        .rate   = &saffirepro_both_rate_spec,
        .meter  = NULL
 };
 
-static struct snd_bebob_rate_spec saffire_both_rate_spec = {
+static const struct snd_bebob_rate_spec saffire_both_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-static struct snd_bebob_clock_spec saffire_both_clk_spec = {
+static const struct snd_bebob_clock_spec saffire_both_clk_spec = {
        .num    = ARRAY_SIZE(saffire_both_clk_src_types),
        .types  = saffire_both_clk_src_types,
        .get    = &saffire_both_clk_src_get,
 };
 /* Saffire LE */
-static struct snd_bebob_meter_spec saffire_le_meter_spec = {
+static const struct snd_bebob_meter_spec saffire_le_meter_spec = {
        .num    = ARRAY_SIZE(saffire_le_meter_labels),
        .labels = saffire_le_meter_labels,
        .get    = &saffire_meter_get,
 };
-struct snd_bebob_spec saffire_le_spec = {
+const struct snd_bebob_spec saffire_le_spec = {
        .clock  = &saffire_both_clk_spec,
        .rate   = &saffire_both_rate_spec,
        .meter  = &saffire_le_meter_spec
 };
 /* Saffire */
-static struct snd_bebob_meter_spec saffire_meter_spec = {
+static const struct snd_bebob_meter_spec saffire_meter_spec = {
        .num    = ARRAY_SIZE(saffire_meter_labels),
        .labels = saffire_meter_labels,
        .get    = &saffire_meter_get,
 };
-struct snd_bebob_spec saffire_spec = {
+const struct snd_bebob_spec saffire_spec = {
        .clock  = &saffire_both_clk_spec,
        .rate   = &saffire_both_rate_spec,
        .meter  = &saffire_meter_spec
index 057495d54ab029e7f1fc5b1b7cf630ee20c3c817..07e5abdbceb59cec189726d79ee5d200d452e53b 100644 (file)
@@ -628,7 +628,7 @@ static const char *const special_meter_labels[] = {
 static int
 special_meter_get(struct snd_bebob *bebob, u32 *target, unsigned int size)
 {
-       u16 *buf;
+       __be16 *buf;
        unsigned int i, c, channels;
        int err;
 
@@ -687,7 +687,7 @@ static const char *const nrv10_meter_labels[] = {
 static int
 normal_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
 {
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        unsigned int c, channels;
        int err;
 
@@ -712,85 +712,85 @@ end:
 }
 
 /* for special customized devices */
-static struct snd_bebob_rate_spec special_rate_spec = {
+static const struct snd_bebob_rate_spec special_rate_spec = {
        .get    = &special_get_rate,
        .set    = &special_set_rate,
 };
-static struct snd_bebob_clock_spec special_clk_spec = {
+static const struct snd_bebob_clock_spec special_clk_spec = {
        .num    = ARRAY_SIZE(special_clk_types),
        .types  = special_clk_types,
        .get    = &special_clk_get,
 };
-static struct snd_bebob_meter_spec special_meter_spec = {
+static const struct snd_bebob_meter_spec special_meter_spec = {
        .num    = ARRAY_SIZE(special_meter_labels),
        .labels = special_meter_labels,
        .get    = &special_meter_get
 };
-struct snd_bebob_spec maudio_special_spec = {
+const struct snd_bebob_spec maudio_special_spec = {
        .clock  = &special_clk_spec,
        .rate   = &special_rate_spec,
        .meter  = &special_meter_spec
 };
 
 /* Firewire 410 specification */
-static struct snd_bebob_rate_spec usual_rate_spec = {
+static const struct snd_bebob_rate_spec usual_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-static struct snd_bebob_meter_spec fw410_meter_spec = {
+static const struct snd_bebob_meter_spec fw410_meter_spec = {
        .num    = ARRAY_SIZE(fw410_meter_labels),
        .labels = fw410_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_fw410_spec = {
+const struct snd_bebob_spec maudio_fw410_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &fw410_meter_spec
 };
 
 /* Firewire Audiophile specification */
-static struct snd_bebob_meter_spec audiophile_meter_spec = {
+static const struct snd_bebob_meter_spec audiophile_meter_spec = {
        .num    = ARRAY_SIZE(audiophile_meter_labels),
        .labels = audiophile_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_audiophile_spec = {
+const struct snd_bebob_spec maudio_audiophile_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &audiophile_meter_spec
 };
 
 /* Firewire Solo specification */
-static struct snd_bebob_meter_spec solo_meter_spec = {
+static const struct snd_bebob_meter_spec solo_meter_spec = {
        .num    = ARRAY_SIZE(solo_meter_labels),
        .labels = solo_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_solo_spec = {
+const struct snd_bebob_spec maudio_solo_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &solo_meter_spec
 };
 
 /* Ozonic specification */
-static struct snd_bebob_meter_spec ozonic_meter_spec = {
+static const struct snd_bebob_meter_spec ozonic_meter_spec = {
        .num    = ARRAY_SIZE(ozonic_meter_labels),
        .labels = ozonic_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_ozonic_spec = {
+const struct snd_bebob_spec maudio_ozonic_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &ozonic_meter_spec
 };
 
 /* NRV10 specification */
-static struct snd_bebob_meter_spec nrv10_meter_spec = {
+static const struct snd_bebob_meter_spec nrv10_meter_spec = {
        .num    = ARRAY_SIZE(nrv10_meter_labels),
        .labels = nrv10_meter_labels,
        .get    = &normal_meter_get
 };
-struct snd_bebob_spec maudio_nrv10_spec = {
+const struct snd_bebob_spec maudio_nrv10_spec = {
        .clock  = NULL,
        .rate   = &usual_rate_spec,
        .meter  = &nrv10_meter_spec
index 5681143925cda919987350a9a054fc47cf1b0a1e..90d95be499b079c5d32c99b1b7b56a409ac377ec 100644 (file)
@@ -72,11 +72,11 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&bebob->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&bebob->tx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&bebob->tx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&bebob->tx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&bebob->tx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&bebob->lock, flags);
 }
@@ -89,11 +89,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&bebob->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&bebob->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&bebob->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&bebob->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&bebob->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&bebob->lock, flags);
 }
index c0f018a61fdc039b0e331a40d9bed4e305645320..ef224d6f5c248d0d28cf9754f96f20b8fc99df5c 100644 (file)
@@ -122,11 +122,11 @@ pcm_init_hw_params(struct snd_bebob *bebob,
                           SNDRV_PCM_INFO_MMAP_VALID;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
                s = &bebob->tx_stream;
                formations = bebob->tx_stream_formations;
        } else {
-               runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
                s = &bebob->rx_stream;
                formations = bebob->rx_stream_formations;
        }
@@ -146,7 +146,7 @@ pcm_init_hw_params(struct snd_bebob *bebob,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
 end:
        return err;
 }
@@ -155,7 +155,7 @@ static int
 pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_bebob *bebob = substream->private_data;
-       struct snd_bebob_rate_spec *spec = bebob->spec->rate;
+       const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
        unsigned int sampling_rate;
        enum snd_bebob_clock_type src;
        int err;
@@ -220,8 +220,8 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&bebob->substreams_counter);
-       amdtp_stream_set_pcm_format(&bebob->tx_stream,
-                                   params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&bebob->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -239,8 +239,8 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&bebob->substreams_counter);
-       amdtp_stream_set_pcm_format(&bebob->rx_stream,
-                                   params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&bebob->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 301cc6a9394542817c9d17feda1b87da4505b65c..ec24f96794f50794737578c93d06261a9d93330c 100644 (file)
@@ -73,7 +73,7 @@ proc_read_meters(struct snd_info_entry *entry,
                 struct snd_info_buffer *buffer)
 {
        struct snd_bebob *bebob = entry->private_data;
-       struct snd_bebob_meter_spec *spec = bebob->spec->meter;
+       const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
        u32 *buf;
        unsigned int i, c, channels, size;
 
@@ -138,8 +138,8 @@ proc_read_clock(struct snd_info_entry *entry,
                "SYT-Match",
        };
        struct snd_bebob *bebob = entry->private_data;
-       struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        enum snd_bebob_clock_type src;
        unsigned int rate;
 
index 5be5242e1ed86a535b875346429f5113d37dcad5..926e5dcbb66a1a3ec523482ceb5e199f8c455b64 100644 (file)
@@ -119,7 +119,7 @@ end:
 int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
                                   enum snd_bebob_clock_type *src)
 {
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
        unsigned int id;
        enum avc_bridgeco_plug_type type;
@@ -338,7 +338,7 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
                                        err = -ENOSYS;
                                        goto end;
                                }
-                               s->midi_position = stm_pos;
+                               amdtp_am824_set_midi_position(s, stm_pos);
                                midi = stm_pos;
                                break;
                        /* for PCM data channel */
@@ -354,11 +354,12 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
                        case 0x09:      /* Digital */
                        default:
                                location = pcm + sec_loc;
-                               if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) {
+                               if (location >= AM824_MAX_CHANNELS_FOR_PCM) {
                                        err = -ENOSYS;
                                        goto end;
                                }
-                               s->pcm_positions[location] = stm_pos;
+                               amdtp_am824_set_pcm_position(s, location,
+                                                            stm_pos);
                                break;
                        }
                }
@@ -427,12 +428,19 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate)
        index = get_formation_index(rate);
        pcm_channels = bebob->tx_stream_formations[index].pcm;
        midi_channels = bebob->tx_stream_formations[index].midi;
-       amdtp_stream_set_parameters(&bebob->tx_stream,
-                                   rate, pcm_channels, midi_channels * 8);
+       err = amdtp_am824_set_parameters(&bebob->tx_stream, rate,
+                                        pcm_channels, midi_channels * 8,
+                                        false);
+       if (err < 0)
+               goto end;
+
        pcm_channels = bebob->rx_stream_formations[index].pcm;
        midi_channels = bebob->rx_stream_formations[index].midi;
-       amdtp_stream_set_parameters(&bebob->rx_stream,
-                                   rate, pcm_channels, midi_channels * 8);
+       err = amdtp_am824_set_parameters(&bebob->rx_stream, rate,
+                                        pcm_channels, midi_channels * 8,
+                                        false);
+       if (err < 0)
+               goto end;
 
        /* establish connections for both streams */
        err = cmp_connection_establish(&bebob->out_conn,
@@ -530,8 +538,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_init(&bebob->tx_stream, bebob->unit,
-                               AMDTP_IN_STREAM, CIP_BLOCKING);
+       err = amdtp_am824_init(&bebob->tx_stream, bebob->unit,
+                              AMDTP_IN_STREAM, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(&bebob->tx_stream);
                destroy_both_connections(bebob);
@@ -559,8 +567,8 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
        if (bebob->maudio_special_quirk)
                bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
 
-       err = amdtp_stream_init(&bebob->rx_stream, bebob->unit,
-                               AMDTP_OUT_STREAM, CIP_BLOCKING);
+       err = amdtp_am824_init(&bebob->rx_stream, bebob->unit,
+                              AMDTP_OUT_STREAM, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(&bebob->tx_stream);
                amdtp_stream_destroy(&bebob->rx_stream);
@@ -572,7 +580,7 @@ end:
 
 int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
 {
-       struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
+       const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
        struct amdtp_stream *master, *slave;
        enum cip_flags sync_mode;
        unsigned int curr_rate;
@@ -864,8 +872,8 @@ parse_stream_formation(u8 *buf, unsigned int len,
                }
        }
 
-       if (formation[i].pcm  > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
+       if (formation[i].pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
+           formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI)
                return -ENOSYS;
 
        return 0;
@@ -959,7 +967,7 @@ end:
 
 int snd_bebob_stream_discover(struct snd_bebob *bebob)
 {
-       struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
+       const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
        u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
        enum avc_bridgeco_plug_type type;
        unsigned int i;
index 9242e33d2cf1c1d26dc83680315c82c006332164..c38358b82ada0ac909ff9e999ee3f57761b5a632 100644 (file)
@@ -55,30 +55,30 @@ phase24_series_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
        return 0;
 }
 
-static struct snd_bebob_rate_spec phase_series_rate_spec = {
+static const struct snd_bebob_rate_spec phase_series_rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
 
 /* PHASE 88 Rack FW */
-static struct snd_bebob_clock_spec phase88_rack_clk = {
+static const struct snd_bebob_clock_spec phase88_rack_clk = {
        .num    = ARRAY_SIZE(phase88_rack_clk_src_types),
        .types  = phase88_rack_clk_src_types,
        .get    = &phase88_rack_clk_src_get,
 };
-struct snd_bebob_spec phase88_rack_spec = {
+const struct snd_bebob_spec phase88_rack_spec = {
        .clock  = &phase88_rack_clk,
        .rate   = &phase_series_rate_spec,
        .meter  = NULL
 };
 
 /* 'PHASE 24 FW' and 'PHASE X24 FW' */
-static struct snd_bebob_clock_spec phase24_series_clk = {
+static const struct snd_bebob_clock_spec phase24_series_clk = {
        .num    = ARRAY_SIZE(phase24_series_clk_src_types),
        .types  = phase24_series_clk_src_types,
        .get    = &phase24_series_clk_src_get,
 };
-struct snd_bebob_spec phase24_series_spec = {
+const struct snd_bebob_spec phase24_series_spec = {
        .clock  = &phase24_series_clk,
        .rate   = &phase_series_rate_spec,
        .meter  = NULL
index 58101702410b64b17e1733fc3a643221f9d62e86..90d4404f77ce07d1ec98af09aea4463d7fdce25d 100644 (file)
@@ -46,16 +46,16 @@ clk_src_get(struct snd_bebob *bebob, unsigned int *id)
 
        return 0;
 }
-static struct snd_bebob_clock_spec clock_spec = {
+static const struct snd_bebob_clock_spec clock_spec = {
        .num    = ARRAY_SIZE(clk_src_types),
        .types  = clk_src_types,
        .get    = &clk_src_get,
 };
-static struct snd_bebob_rate_spec rate_spec = {
+static const struct snd_bebob_rate_spec rate_spec = {
        .get    = &snd_bebob_stream_get_rate,
        .set    = &snd_bebob_stream_set_rate,
 };
-struct snd_bebob_spec yamaha_go_spec = {
+const struct snd_bebob_spec yamaha_go_spec = {
        .clock  = &clock_spec,
        .rate   = &rate_spec,
        .meter  = NULL
index 9ef228ef7baf2728b4bd8fb9e932c0f3e00dc791..55b4be9b0034093bc221ff1955057f739e299520 100644 (file)
@@ -1,3 +1,3 @@
 snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
                 dice-pcm.o dice-hwdep.o dice.o
-obj-m += snd-dice.o
+obj-$(CONFIG_SND_DICE) += snd-dice.o
index fe43ce791f845dfccdb7e10ce6f9df72ffc1f549..151b09f240f280d14233817ff64ef77d14d3a31b 100644 (file)
@@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&dice->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&dice->tx_stream,
+               amdtp_am824_midi_trigger(&dice->tx_stream,
                                          substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&dice->tx_stream,
+               amdtp_am824_midi_trigger(&dice->tx_stream,
                                          substrm->number, NULL);
 
        spin_unlock_irqrestore(&dice->lock, flags);
@@ -69,11 +69,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&dice->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&dice->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&dice->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&dice->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&dice->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&dice->lock, flags);
 }
index 4e67b1da0fe6ffbe9350b0e17a71a87f2b03e73b..9b3431999fc8b6df8dac3b58c42d6e1604c617e4 100644 (file)
@@ -133,11 +133,11 @@ static int init_hw_info(struct snd_dice *dice,
                   SNDRV_PCM_INFO_BLOCK_TRANSFER;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               hw->formats = AMDTP_IN_PCM_FORMAT_BITS;
+               hw->formats = AM824_IN_PCM_FORMAT_BITS;
                stream = &dice->tx_stream;
                pcm_channels = dice->tx_channels;
        } else {
-               hw->formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               hw->formats = AM824_OUT_PCM_FORMAT_BITS;
                stream = &dice->rx_stream;
                pcm_channels = dice->rx_channels;
        }
@@ -156,7 +156,7 @@ static int init_hw_info(struct snd_dice *dice,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 end:
        return err;
 }
@@ -243,8 +243,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&dice->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&dice->tx_stream,
-                                   params_format(hw_params));
+       amdtp_am824_set_pcm_format(&dice->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -265,8 +264,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&dice->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&dice->rx_stream,
-                                   params_format(hw_params));
+       amdtp_am824_set_pcm_format(&dice->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 07dbd01d7a6bd336d901fa78b83365b44307b1a0..a6a39f7ef58d8e32cf6e6ff60d45bcbbb23b1e04 100644 (file)
@@ -44,16 +44,16 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
 static void release_resources(struct snd_dice *dice,
                              struct fw_iso_resources *resources)
 {
-       unsigned int channel;
+       __be32 channel;
 
        /* Reset channel number */
        channel = cpu_to_be32((u32)-1);
        if (resources == &dice->tx_resources)
                snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-                                             &channel, 4);
+                                             &channel, sizeof(channel));
        else
                snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-                                             &channel, 4);
+                                             &channel, sizeof(channel));
 
        fw_iso_resources_free(resources);
 }
@@ -62,7 +62,7 @@ static int keep_resources(struct snd_dice *dice,
                          struct fw_iso_resources *resources,
                          unsigned int max_payload_bytes)
 {
-       unsigned int channel;
+       __be32 channel;
        int err;
 
        err = fw_iso_resources_allocate(resources, max_payload_bytes,
@@ -74,10 +74,10 @@ static int keep_resources(struct snd_dice *dice,
        channel = cpu_to_be32(resources->channel);
        if (resources == &dice->tx_resources)
                err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-                                                   &channel, 4);
+                                                   &channel, sizeof(channel));
        else
                err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-                                                   &channel, 4);
+                                                   &channel, sizeof(channel));
        if (err < 0)
                release_resources(dice, resources);
 end:
@@ -100,6 +100,7 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 {
        struct fw_iso_resources *resources;
        unsigned int i, mode, pcm_chs, midi_ports;
+       bool double_pcm_frames;
        int err;
 
        err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
@@ -125,21 +126,24 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
         * For this quirk, blocking mode is required and PCM buffer size should
         * be aligned to SYT_INTERVAL.
         */
-       if (mode > 1) {
+       double_pcm_frames = mode > 1;
+       if (double_pcm_frames) {
                rate /= 2;
                pcm_chs *= 2;
-               stream->double_pcm_frames = true;
-       } else {
-               stream->double_pcm_frames = false;
        }
 
-       amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
-       if (mode > 1) {
+       err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
+                                        double_pcm_frames);
+       if (err < 0)
+               goto end;
+
+       if (double_pcm_frames) {
                pcm_chs /= 2;
 
                for (i = 0; i < pcm_chs; i++) {
-                       stream->pcm_positions[i] = i * 2;
-                       stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
+                       amdtp_am824_set_pcm_position(stream, i, i * 2);
+                       amdtp_am824_set_pcm_position(stream, i + pcm_chs,
+                                                    i * 2 + 1);
                }
        }
 
@@ -302,7 +306,7 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
                goto end;
        resources->channels_mask = 0x00000000ffffffffuLL;
 
-       err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
+       err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(stream);
                fw_iso_resources_destroy(resources);
index 70a111d7f428af4a0487f80cf350767935c8cac0..5d99436dfcaee5e70f3957a8f8b59be3d9e213d3 100644 (file)
@@ -29,7 +29,8 @@ static int dice_interface_check(struct fw_unit *unit)
        struct fw_csr_iterator it;
        int key, val, vendor = -1, model = -1, err;
        unsigned int category, i;
-       __be32 *pointers, value;
+       __be32 *pointers;
+       u32 value;
        __be32 version;
 
        pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
index ecf5dc86223544ed848fcfa9918630e74f17e7f9..101550ac1a242fc35af22f9f291b0fc2771d4532 100644 (file)
@@ -34,7 +34,7 @@
 #include <sound/pcm_params.h>
 #include <sound/rawmidi.h>
 
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../iso-resources.h"
 #include "../lib.h"
 #include "dice-interface.h"
diff --git a/sound/firewire/digi00x/Makefile b/sound/firewire/digi00x/Makefile
new file mode 100644 (file)
index 0000000..1123e68
--- /dev/null
@@ -0,0 +1,4 @@
+snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
+                            digi00x-pcm.o digi00x-hwdep.o \
+                            digi00x-transaction.o digi00x-midi.o digi00x.o
+obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o
diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c
new file mode 100644 (file)
index 0000000..b02a5e8
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ * Copyright (C) 2012 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <sound/pcm.h>
+#include "digi00x.h"
+
+#define CIP_FMT_AM             0x10
+
+/* 'Clock-based rate control mode' is just supported. */
+#define AMDTP_FDF_AM824                0x00
+
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND  3093
+
+/*
+ * Several devices look only at the first eight data blocks.
+ * In any case, this is more than enough for the MIDI data rate.
+ */
+#define MAX_MIDI_RX_BLOCKS     8
+
+/*
+ * The double-oh-three algorithm was discovered by Robin Gareus and Damien
+ * Zammit in 2012, with reverse-engineering for Digi 003 Rack.
+ */
+struct dot_state {
+       u8 carry;
+       u8 idx;
+       unsigned int off;
+};
+
+struct amdtp_dot {
+       unsigned int pcm_channels;
+       struct dot_state state;
+
+       unsigned int midi_ports;
+       /* 2 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) */
+       struct snd_rawmidi_substream *midi[2];
+       int midi_fifo_used[2];
+       int midi_fifo_limit;
+
+       void (*transfer_samples)(struct amdtp_stream *s,
+                                struct snd_pcm_substream *pcm,
+                                __be32 *buffer, unsigned int frames);
+};
+
+/*
+ * double-oh-three look up table
+ *
+ * @param idx index byte (audio-sample data) 0x00..0xff
+ * @param off channel offset shift
+ * @return salt to XOR with given data
+ */
+#define BYTE_PER_SAMPLE (4)
+#define MAGIC_DOT_BYTE (2)
+#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
+static const u8 dot_scrt(const u8 idx, const unsigned int off)
+{
+       /*
+        * the length of the added pattern only depends on the lower nibble
+        * of the last non-zero data
+        */
+       static const u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14,
+                                  12, 10, 8, 6, 4, 2, 0};
+
+       /*
+        * the lower nibble of the salt. Interleaved sequence.
+        * this is walked backwards according to len[]
+        */
+       static const u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4,
+                                  0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf};
+
+       /* circular list for the salt's hi nibble. */
+       static const u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4,
+                                  0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa};
+
+       /*
+        * start offset for upper nibble mapping.
+        * note: 9 is /special/. In the case where the high nibble == 0x9,
+        * hir[] is not used and - coincidentally - the salt's hi nibble is
+        * 0x09 regardless of the offset.
+        */
+       static const u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4,
+                                  3, 0x00, 14, 13, 8, 9, 10, 2};
+
+       const u8 ln = idx & 0xf;
+       const u8 hn = (idx >> 4) & 0xf;
+       const u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15];
+
+       if (len[ln] < off)
+               return 0x00;
+
+       return ((nib[14 + off - len[ln]]) | (hr << 4));
+}
+
+static void dot_encode_step(struct dot_state *state, __be32 *const buffer)
+{
+       u8 * const data = (u8 *) buffer;
+
+       if (data[MAGIC_DOT_BYTE] != 0x00) {
+               state->off = 0;
+               state->idx = data[MAGIC_DOT_BYTE] ^ state->carry;
+       }
+       data[MAGIC_DOT_BYTE] ^= state->carry;
+       state->carry = dot_scrt(state->idx, ++(state->off));
+}
+
+int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                            unsigned int pcm_channels)
+{
+       struct amdtp_dot *p = s->protocol;
+       int err;
+
+       if (amdtp_stream_running(s))
+               return -EBUSY;
+
+       /*
+        * A first data channel is for MIDI conformant data channel, the rest is
+        * Multi Bit Linear Audio data channel.
+        */
+       err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1);
+       if (err < 0)
+               return err;
+
+       s->fdf = AMDTP_FDF_AM824 | s->sfc;
+
+       p->pcm_channels = pcm_channels;
+
+       if (s->direction == AMDTP_IN_STREAM)
+               p->midi_ports = DOT_MIDI_IN_PORTS;
+       else
+               p->midi_ports = DOT_MIDI_OUT_PORTS;
+
+       /*
+        * We do not know the actual MIDI FIFO size of most devices.  Just
+        * assume two bytes, i.e., one byte can be received over the bus while
+        * the previous one is transmitted over MIDI.
+        * (The value here is adjusted for midi_ratelimit_per_packet().)
+        */
+       p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
+
+       return 0;
+}
+
+static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u32 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000);
+                       dot_encode_step(&p->state, &buffer[c]);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_s16(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u16 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32((*src << 8) | 0x40000000);
+                       dot_encode_step(&p->state, &buffer[c]);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
+                        __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_dot *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       u32 *dst;
+
+       channels = p->pcm_channels;
+       dst  = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       buffer++;
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *dst = be32_to_cpu(buffer[c]) << 8;
+                       dst++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       dst = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
+                             unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int channels, i, c;
+
+       channels = p->pcm_channels;
+
+       buffer++;
+       for (i = 0; i < data_blocks; ++i) {
+               for (c = 0; c < channels; ++c)
+                       buffer[c] = cpu_to_be32(0x40000000);
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
+{
+       struct amdtp_dot *p = s->protocol;
+       int used;
+
+       used = p->midi_fifo_used[port];
+       if (used == 0)
+               return true;
+
+       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
+       used = max(used, 0);
+       p->midi_fifo_used[port] = used;
+
+       return used < p->midi_fifo_limit;
+}
+
+static inline void midi_use_bytes(struct amdtp_stream *s,
+                                 unsigned int port, unsigned int count)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       p->midi_fifo_used[port] += amdtp_rate_table[s->sfc] * count;
+}
+
+static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                               unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int f, port;
+       int len;
+       u8 *b;
+
+       for (f = 0; f < data_blocks; f++) {
+               port = (s->data_block_counter + f) % 8;
+               b = (u8 *)&buffer[0];
+
+               len = 0;
+               if (port < p->midi_ports &&
+                   midi_ratelimit_per_packet(s, port) &&
+                   p->midi[port] != NULL)
+                       len = snd_rawmidi_transmit(p->midi[port], b + 1, 2);
+
+               if (len > 0) {
+                       b[3] = (0x10 << port) | len;
+                       midi_use_bytes(s, port, len);
+               } else {
+                       b[1] = 0;
+                       b[2] = 0;
+                       b[3] = 0;
+               }
+               b[0] = 0x80;
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+                              unsigned int data_blocks)
+{
+       struct amdtp_dot *p = s->protocol;
+       unsigned int f, port, len;
+       u8 *b;
+
+       for (f = 0; f < data_blocks; f++) {
+               b = (u8 *)&buffer[0];
+               port = b[3] >> 4;
+               len = b[3] & 0x0f;
+
+               if (port < p->midi_ports && p->midi[port] && len > 0)
+                       snd_rawmidi_receive(p->midi[port], b + 1, len);
+
+               buffer += s->data_block_quadlets;
+       }
+}
+
+int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                    struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       /* This protocol delivers 24 bit data in 32bit data channel. */
+       err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+       if (err < 0)
+               return err;
+
+       return amdtp_stream_add_pcm_hw_constraints(s, runtime);
+}
+
+void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       if (WARN_ON(amdtp_stream_pcm_running(s)))
+               return;
+
+       switch (format) {
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S16:
+               if (s->direction == AMDTP_OUT_STREAM) {
+                       p->transfer_samples = write_pcm_s16;
+                       break;
+               }
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32:
+               if (s->direction == AMDTP_OUT_STREAM)
+                       p->transfer_samples = write_pcm_s32;
+               else
+                       p->transfer_samples = read_pcm_s32;
+               break;
+       }
+}
+
+void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                         struct snd_rawmidi_substream *midi)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       if (port < p->midi_ports)
+               ACCESS_ONCE(p->midi[port]) = midi;
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks;
+       } else {
+               pcm_frames = 0;
+       }
+
+       read_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_dot *p = (struct amdtp_dot *)s->protocol;
+       struct snd_pcm_substream *pcm;
+       unsigned int pcm_frames;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm) {
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+               pcm_frames = data_blocks;
+       } else {
+               write_pcm_silence(s, buffer, data_blocks);
+               pcm_frames = 0;
+       }
+
+       write_midi_messages(s, buffer, data_blocks);
+
+       return pcm_frames;
+}
+
+int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
+                enum amdtp_stream_direction dir)
+{
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+       enum cip_flags flags;
+
+       /* Use different mode between incoming/outgoing. */
+       if (dir == AMDTP_IN_STREAM) {
+               flags = CIP_NONBLOCKING | CIP_SKIP_INIT_DBC_CHECK;
+               process_data_blocks = process_tx_data_blocks;
+       } else {
+               flags = CIP_BLOCKING;
+               process_data_blocks = process_rx_data_blocks;
+       }
+
+       return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
+                                process_data_blocks, sizeof(struct amdtp_dot));
+}
+
+void amdtp_dot_reset(struct amdtp_stream *s)
+{
+       struct amdtp_dot *p = s->protocol;
+
+       p->state.carry = 0x00;
+       p->state.idx = 0x00;
+       p->state.off = 0;
+}
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
new file mode 100644 (file)
index 0000000..f188e47
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes give three functionality.
+ *
+ * 1.get firewire node information
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock stream
+ * 4.get asynchronous messaging
+ */
+
+#include "digi00x.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
+                      loff_t *offset)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+       DEFINE_WAIT(wait);
+       union snd_firewire_event event;
+
+       spin_lock_irq(&dg00x->lock);
+
+       while (!dg00x->dev_lock_changed && dg00x->msg == 0) {
+               prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+               spin_unlock_irq(&dg00x->lock);
+               schedule();
+               finish_wait(&dg00x->hwdep_wait, &wait);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               spin_lock_irq(&dg00x->lock);
+       }
+
+       memset(&event, 0, sizeof(event));
+       if (dg00x->dev_lock_changed) {
+               event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+               event.lock_status.status = (dg00x->dev_lock_count > 0);
+               dg00x->dev_lock_changed = false;
+
+               count = min_t(long, count, sizeof(event.lock_status));
+       } else {
+               event.digi00x_message.type =
+                                       SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE;
+               event.digi00x_message.message = dg00x->msg;
+               dg00x->msg = 0;
+
+               count = min_t(long, count, sizeof(event.digi00x_message));
+       }
+
+       spin_unlock_irq(&dg00x->lock);
+
+       if (copy_to_user(buf, &event, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+                              poll_table *wait)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+       unsigned int events;
+
+       poll_wait(file, &dg00x->hwdep_wait, wait);
+
+       spin_lock_irq(&dg00x->lock);
+       if (dg00x->dev_lock_changed || dg00x->msg)
+               events = POLLIN | POLLRDNORM;
+       else
+               events = 0;
+       spin_unlock_irq(&dg00x->lock);
+
+       return events;
+}
+
+static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
+{
+       struct fw_device *dev = fw_parent_device(dg00x->unit);
+       struct snd_firewire_get_info info;
+
+       memset(&info, 0, sizeof(info));
+       info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;
+       info.card = dev->card->index;
+       *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+       *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+       strlcpy(info.device_name, dev_name(&dev->device),
+               sizeof(info.device_name));
+
+       if (copy_to_user(arg, &info, sizeof(info)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int hwdep_lock(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       spin_lock_irq(&dg00x->lock);
+
+       if (dg00x->dev_lock_count == 0) {
+               dg00x->dev_lock_count = -1;
+               err = 0;
+       } else {
+               err = -EBUSY;
+       }
+
+       spin_unlock_irq(&dg00x->lock);
+
+       return err;
+}
+
+static int hwdep_unlock(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       spin_lock_irq(&dg00x->lock);
+
+       if (dg00x->dev_lock_count == -1) {
+               dg00x->dev_lock_count = 0;
+               err = 0;
+       } else {
+               err = -EBADFD;
+       }
+
+       spin_unlock_irq(&dg00x->lock);
+
+       return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+
+       spin_lock_irq(&dg00x->lock);
+       if (dg00x->dev_lock_count == -1)
+               dg00x->dev_lock_count = 0;
+       spin_unlock_irq(&dg00x->lock);
+
+       return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+           unsigned int cmd, unsigned long arg)
+{
+       struct snd_dg00x *dg00x = hwdep->private_data;
+
+       switch (cmd) {
+       case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+               return hwdep_get_info(dg00x, (void __user *)arg);
+       case SNDRV_FIREWIRE_IOCTL_LOCK:
+               return hwdep_lock(dg00x);
+       case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+               return hwdep_unlock(dg00x);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+                             unsigned int cmd, unsigned long arg)
+{
+       return hwdep_ioctl(hwdep, file, cmd,
+                          (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+static const struct snd_hwdep_ops hwdep_ops = {
+       .read           = hwdep_read,
+       .release        = hwdep_release,
+       .poll           = hwdep_poll,
+       .ioctl          = hwdep_ioctl,
+       .ioctl_compat   = hwdep_compat_ioctl,
+};
+
+int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
+{
+       struct snd_hwdep *hwdep;
+       int err;
+
+       err = snd_hwdep_new(dg00x->card, "Digi00x", 0, &hwdep);
+       if (err < 0)
+               return err;
+
+       strcpy(hwdep->name, "Digi00x");
+       hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
+       hwdep->ops = hwdep_ops;
+       hwdep->private_data = dg00x;
+       hwdep->exclusive = true;
+
+       return err;
+}
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
new file mode 100644 (file)
index 0000000..1a72a38
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "digi00x.h"
+
+static int midi_phys_open(struct snd_rawmidi_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+       int err;
+
+       err = snd_dg00x_stream_lock_try(dg00x);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&dg00x->mutex);
+       dg00x->substreams_counter++;
+       err = snd_dg00x_stream_start_duplex(dg00x, 0);
+       mutex_unlock(&dg00x->mutex);
+       if (err < 0)
+               snd_dg00x_stream_lock_release(dg00x);
+
+       return err;
+}
+
+static int midi_phys_close(struct snd_rawmidi_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+
+       mutex_lock(&dg00x->mutex);
+       dg00x->substreams_counter--;
+       snd_dg00x_stream_stop_duplex(dg00x);
+       mutex_unlock(&dg00x->mutex);
+
+       snd_dg00x_stream_lock_release(dg00x);
+       return 0;
+}
+
+static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream,
+                                     int up)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dg00x->lock, flags);
+
+       if (up)
+               amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number,
+                                      substream);
+       else
+               amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number,
+                                      NULL);
+
+       spin_unlock_irqrestore(&dg00x->lock, flags);
+}
+
+static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
+                                      int up)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dg00x->lock, flags);
+
+       if (up)
+               amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number,
+                                      substream);
+       else
+               amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number,
+                                      NULL);
+
+       spin_unlock_irqrestore(&dg00x->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_phys_capture_ops = {
+       .open           = midi_phys_open,
+       .close          = midi_phys_close,
+       .trigger        = midi_phys_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_phys_playback_ops = {
+       .open           = midi_phys_open,
+       .close          = midi_phys_close,
+       .trigger        = midi_phys_playback_trigger,
+};
+
+static int midi_ctl_open(struct snd_rawmidi_substream *substream)
+{
+       /* Do nothing. */
+       return 0;
+}
+
+static int midi_ctl_capture_close(struct snd_rawmidi_substream *substream)
+{
+       /* Do nothing. */
+       return 0;
+}
+
+static int midi_ctl_playback_close(struct snd_rawmidi_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+
+       snd_fw_async_midi_port_finish(&dg00x->out_control);
+
+       return 0;
+}
+
+static void midi_ctl_capture_trigger(struct snd_rawmidi_substream *substream,
+                                    int up)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dg00x->lock, flags);
+
+       if (up)
+               dg00x->in_control = substream;
+       else
+               dg00x->in_control = NULL;
+
+       spin_unlock_irqrestore(&dg00x->lock, flags);
+}
+
+static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream,
+                                     int up)
+{
+       struct snd_dg00x *dg00x = substream->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dg00x->lock, flags);
+
+       if (up)
+               snd_fw_async_midi_port_run(&dg00x->out_control, substream);
+
+       spin_unlock_irqrestore(&dg00x->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_ctl_capture_ops = {
+       .open           = midi_ctl_open,
+       .close          = midi_ctl_capture_close,
+       .trigger        = midi_ctl_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_ctl_playback_ops = {
+       .open           = midi_ctl_open,
+       .close          = midi_ctl_playback_close,
+       .trigger        = midi_ctl_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_dg00x *dg00x,
+                                    struct snd_rawmidi_str *str,
+                                    bool is_ctl)
+{
+       struct snd_rawmidi_substream *subs;
+
+       list_for_each_entry(subs, &str->substreams, list) {
+               if (!is_ctl)
+                       snprintf(subs->name, sizeof(subs->name),
+                                "%s MIDI %d",
+                                dg00x->card->shortname, subs->number + 1);
+               else
+                       /* This port is for asynchronous transaction. */
+                       snprintf(subs->name, sizeof(subs->name),
+                                "%s control",
+                                dg00x->card->shortname);
+       }
+}
+
+int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
+{
+       struct snd_rawmidi *rmidi[2];
+       struct snd_rawmidi_str *str;
+       unsigned int i;
+       int err;
+
+       /* Add physical midi ports. */
+       err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
+                       DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, &rmidi[0]);
+       if (err < 0)
+               return err;
+
+       snprintf(rmidi[0]->name, sizeof(rmidi[0]->name),
+                "%s MIDI", dg00x->card->shortname);
+
+       snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
+                           &midi_phys_capture_ops);
+       snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &midi_phys_playback_ops);
+
+       /* Add a pair of control midi ports. */
+       err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1,
+                             1, 1, &rmidi[1]);
+       if (err < 0)
+               return err;
+
+       snprintf(rmidi[1]->name, sizeof(rmidi[1]->name),
+                "%s control", dg00x->card->shortname);
+
+       snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT,
+                           &midi_ctl_capture_ops);
+       snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &midi_ctl_playback_ops);
+
+       for (i = 0; i < ARRAY_SIZE(rmidi); i++) {
+               rmidi[i]->private_data = dg00x;
+
+               rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+               str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+               set_midi_substream_names(dg00x, str, i);
+
+               rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+               str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+               set_midi_substream_names(dg00x, str, i);
+
+               rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+       }
+
+       return 0;
+}
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
new file mode 100644 (file)
index 0000000..cac28f7
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "digi00x.h"
+
+static int hw_rule_rate(struct snd_pcm_hw_params *params,
+                       struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *r =
+               hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       const struct snd_interval *c =
+               hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval t = {
+               .min = UINT_MAX, .max = 0, .integer = 1,
+       };
+       unsigned int i;
+
+       for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
+               if (!snd_interval_test(c,
+                                      snd_dg00x_stream_pcm_channels[i]))
+                       continue;
+
+               t.min = min(t.min, snd_dg00x_stream_rates[i]);
+               t.max = max(t.max, snd_dg00x_stream_rates[i]);
+       }
+
+       return snd_interval_refine(r, &t);
+}
+
+static int hw_rule_channels(struct snd_pcm_hw_params *params,
+                           struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *c =
+               hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       const struct snd_interval *r =
+               hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval t = {
+               .min = UINT_MAX, .max = 0, .integer = 1,
+       };
+       unsigned int i;
+
+       for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
+               if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
+                       continue;
+
+               t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
+               t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
+       }
+
+       return snd_interval_refine(c, &t);
+}
+
+static int pcm_init_hw_params(struct snd_dg00x *dg00x,
+                             struct snd_pcm_substream *substream)
+{
+       static const struct snd_pcm_hardware hardware = {
+               .info = SNDRV_PCM_INFO_BATCH |
+                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                       SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_JOINT_DUPLEX |
+                       SNDRV_PCM_INFO_MMAP |
+                       SNDRV_PCM_INFO_MMAP_VALID,
+               .rates = SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 |
+                        SNDRV_PCM_RATE_96000,
+               .rate_min = 44100,
+               .rate_max = 96000,
+               .channels_min = 10,
+               .channels_max = 18,
+               .period_bytes_min = 4 * 18,
+               .period_bytes_max = 4 * 18 * 2048,
+               .buffer_bytes_max = 4 * 18 * 2048 * 2,
+               .periods_min = 2,
+               .periods_max = UINT_MAX,
+       };
+       struct amdtp_stream *s;
+       int err;
+
+       substream->runtime->hw = hardware;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
+               s = &dg00x->tx_stream;
+       } else {
+               substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16 |
+                                                SNDRV_PCM_FMTBIT_S32;
+               s = &dg00x->rx_stream;
+       }
+
+       err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS,
+                                 hw_rule_channels, NULL,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               return err;
+
+       err = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+                                 hw_rule_rate, NULL,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (err < 0)
+               return err;
+
+       return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+       enum snd_dg00x_clock clock;
+       bool detect;
+       unsigned int rate;
+       int err;
+
+       err = snd_dg00x_stream_lock_try(dg00x);
+       if (err < 0)
+               goto end;
+
+       err = pcm_init_hw_params(dg00x, substream);
+       if (err < 0)
+               goto err_locked;
+
+       /* Check current clock source. */
+       err = snd_dg00x_stream_get_clock(dg00x, &clock);
+       if (err < 0)
+               goto err_locked;
+       if (clock != SND_DG00X_CLOCK_INTERNAL) {
+               err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
+               if (err < 0)
+                       goto err_locked;
+               if (!detect) {
+                       err = -EBUSY;
+                       goto err_locked;
+               }
+       }
+
+       if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
+           amdtp_stream_pcm_running(&dg00x->rx_stream) ||
+           amdtp_stream_pcm_running(&dg00x->tx_stream)) {
+               err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
+               if (err < 0)
+                       goto err_locked;
+               substream->runtime->hw.rate_min = rate;
+               substream->runtime->hw.rate_max = rate;
+       }
+
+       snd_pcm_set_sync(substream);
+end:
+       return err;
+err_locked:
+       snd_dg00x_stream_lock_release(dg00x);
+       return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+
+       snd_dg00x_stream_lock_release(dg00x);
+
+       return 0;
+}
+
+static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+       int err;
+
+       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               mutex_lock(&dg00x->mutex);
+               dg00x->substreams_counter++;
+               mutex_unlock(&dg00x->mutex);
+       }
+
+       amdtp_dot_set_pcm_format(&dg00x->tx_stream, params_format(hw_params));
+
+       return 0;
+}
+
+static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+       int err;
+
+       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               mutex_lock(&dg00x->mutex);
+               dg00x->substreams_counter++;
+               mutex_unlock(&dg00x->mutex);
+       }
+
+       amdtp_dot_set_pcm_format(&dg00x->rx_stream, params_format(hw_params));
+
+       return 0;
+}
+
+static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+
+       mutex_lock(&dg00x->mutex);
+
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+               dg00x->substreams_counter--;
+
+       snd_dg00x_stream_stop_duplex(dg00x);
+
+       mutex_unlock(&dg00x->mutex);
+
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+
+       mutex_lock(&dg00x->mutex);
+
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+               dg00x->substreams_counter--;
+
+       snd_dg00x_stream_stop_duplex(dg00x);
+
+       mutex_unlock(&dg00x->mutex);
+
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       mutex_lock(&dg00x->mutex);
+
+       err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+       if (err >= 0)
+               amdtp_stream_pcm_prepare(&dg00x->tx_stream);
+
+       mutex_unlock(&dg00x->mutex);
+
+       return err;
+}
+
+static int pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       mutex_lock(&dg00x->mutex);
+
+       err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+       if (err >= 0) {
+               amdtp_stream_pcm_prepare(&dg00x->rx_stream);
+               amdtp_dot_reset(&dg00x->rx_stream);
+       }
+
+       mutex_unlock(&dg00x->mutex);
+
+       return err;
+}
+
+static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_dg00x *dg00x = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
+{
+       struct snd_dg00x *dg00x = sbstrm->private_data;
+
+       return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
+}
+
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
+{
+       struct snd_dg00x *dg00x = sbstrm->private_data;
+
+       return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
+}
+
+static struct snd_pcm_ops pcm_capture_ops = {
+       .open           = pcm_open,
+       .close          = pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pcm_capture_hw_params,
+       .hw_free        = pcm_capture_hw_free,
+       .prepare        = pcm_capture_prepare,
+       .trigger        = pcm_capture_trigger,
+       .pointer        = pcm_capture_pointer,
+       .page           = snd_pcm_lib_get_vmalloc_page,
+};
+
+static struct snd_pcm_ops pcm_playback_ops = {
+       .open           = pcm_open,
+       .close          = pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pcm_playback_hw_params,
+       .hw_free        = pcm_playback_hw_free,
+       .prepare        = pcm_playback_prepare,
+       .trigger        = pcm_playback_trigger,
+       .pointer        = pcm_playback_pointer,
+       .page           = snd_pcm_lib_get_vmalloc_page,
+       .mmap           = snd_pcm_lib_mmap_vmalloc,
+};
+
+int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = dg00x;
+       snprintf(pcm->name, sizeof(pcm->name),
+                "%s PCM", dg00x->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+
+       return 0;
+}
diff --git a/sound/firewire/digi00x/digi00x-proc.c b/sound/firewire/digi00x/digi00x-proc.c
new file mode 100644 (file)
index 0000000..a1d601f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * digi00x-proc.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "digi00x.h"
+
+static int get_optical_iface_mode(struct snd_dg00x *dg00x,
+                                 enum snd_dg00x_optical_mode *mode)
+{
+       __be32 data;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_OPT_IFACE_MODE,
+                                &data, sizeof(data), 0);
+       if (err >= 0)
+               *mode = be32_to_cpu(data) & 0x01;
+
+       return err;
+}
+
+static void proc_read_clock(struct snd_info_entry *entry,
+                           struct snd_info_buffer *buf)
+{
+       static const char *const source_name[] = {
+               [SND_DG00X_CLOCK_INTERNAL] = "internal",
+               [SND_DG00X_CLOCK_SPDIF] = "s/pdif",
+               [SND_DG00X_CLOCK_ADAT] = "adat",
+               [SND_DG00X_CLOCK_WORD] = "word clock",
+       };
+       static const char *const optical_name[] = {
+               [SND_DG00X_OPT_IFACE_MODE_ADAT] = "adat",
+               [SND_DG00X_OPT_IFACE_MODE_SPDIF] = "s/pdif",
+       };
+       struct snd_dg00x *dg00x = entry->private_data;
+       enum snd_dg00x_optical_mode mode;
+       unsigned int rate;
+       enum snd_dg00x_clock clock;
+       bool detect;
+
+       if (get_optical_iface_mode(dg00x, &mode) < 0)
+               return;
+       if (snd_dg00x_stream_get_local_rate(dg00x, &rate) < 0)
+               return;
+       if (snd_dg00x_stream_get_clock(dg00x, &clock) < 0)
+               return;
+
+       snd_iprintf(buf, "Optical mode: %s\n", optical_name[mode]);
+       snd_iprintf(buf, "Sampling Rate: %d\n", rate);
+       snd_iprintf(buf, "Clock Source: %s\n", source_name[clock]);
+
+       if (clock == SND_DG00X_CLOCK_INTERNAL)
+               return;
+
+       if (snd_dg00x_stream_check_external_clock(dg00x, &detect) < 0)
+               return;
+       snd_iprintf(buf, "External source: %s\n", detect ? "detected" : "not");
+       if (!detect)
+               return;
+
+       if (snd_dg00x_stream_get_external_rate(dg00x, &rate) >= 0)
+               snd_iprintf(buf, "External sampling rate: %d\n", rate);
+}
+
+void snd_dg00x_proc_init(struct snd_dg00x *dg00x)
+{
+       struct snd_info_entry *root, *entry;
+
+       /*
+        * All nodes are automatically removed at snd_card_disconnect(),
+        * by following to link list.
+        */
+       root = snd_info_create_card_entry(dg00x->card, "firewire",
+                                         dg00x->card->proc_root);
+       if (root == NULL)
+               return;
+
+       root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       if (snd_info_register(root) < 0) {
+               snd_info_free_entry(root);
+               return;
+       }
+
+       entry = snd_info_create_card_entry(dg00x->card, "clock", root);
+       if (entry == NULL) {
+               snd_info_free_entry(root);
+               return;
+       }
+
+       snd_info_set_text_ops(entry, dg00x, proc_read_clock);
+       if (snd_info_register(entry) < 0) {
+               snd_info_free_entry(entry);
+               snd_info_free_entry(root);
+       }
+}
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
new file mode 100644 (file)
index 0000000..4d3b4eb
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "digi00x.h"
+
+#define CALLBACK_TIMEOUT 500
+
+const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
+       [SND_DG00X_RATE_44100] = 44100,
+       [SND_DG00X_RATE_48000] = 48000,
+       [SND_DG00X_RATE_88200] = 88200,
+       [SND_DG00X_RATE_96000] = 96000,
+};
+
+/* Multi Bit Linear Audio data channels for each sampling transfer frequency. */
+const unsigned int
+snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
+       /* Analog/ADAT/SPDIF */
+       [SND_DG00X_RATE_44100] = (8 + 8 + 2),
+       [SND_DG00X_RATE_48000] = (8 + 8 + 2),
+       /* Analog/SPDIF */
+       [SND_DG00X_RATE_88200] = (8 + 2),
+       [SND_DG00X_RATE_96000] = (8 + 2),
+};
+
+int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
+{
+       u32 data;
+       __be32 reg;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       data = be32_to_cpu(reg) & 0x0f;
+       if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
+               *rate = snd_dg00x_stream_rates[data];
+       else
+               err = -EIO;
+
+       return err;
+}
+
+int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
+{
+       __be32 reg;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
+               if (rate == snd_dg00x_stream_rates[i])
+                       break;
+       }
+       if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
+               return -EINVAL;
+
+       reg = cpu_to_be32(i);
+       return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
+                                 &reg, sizeof(reg), 0);
+}
+
+int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
+                              enum snd_dg00x_clock *clock)
+{
+       __be32 reg;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       *clock = be32_to_cpu(reg) & 0x0f;
+       if (*clock >= SND_DG00X_CLOCK_COUNT)
+               err = -EIO;
+
+       return err;
+}
+
+int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
+{
+       __be32 reg;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
+                                &reg, sizeof(reg), 0);
+       if (err >= 0)
+               *detect = be32_to_cpu(reg) > 0;
+
+       return err;
+}
+
+int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
+                                      unsigned int *rate)
+{
+       u32 data;
+       __be32 reg;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       data = be32_to_cpu(reg) & 0x0f;
+       if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
+               *rate = snd_dg00x_stream_rates[data];
+       /* This means desync. */
+       else
+               err = -EBUSY;
+
+       return err;
+}
+
+static void finish_session(struct snd_dg00x *dg00x)
+{
+       __be32 data = cpu_to_be32(0x00000003);
+
+       snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
+                          &data, sizeof(data), 0);
+}
+
+static int begin_session(struct snd_dg00x *dg00x)
+{
+       __be32 data;
+       u32 curr;
+       int err;
+
+       err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
+                                &data, sizeof(data), 0);
+       if (err < 0)
+               goto error;
+       curr = be32_to_cpu(data);
+
+       if (curr == 0)
+               curr = 2;
+
+       curr--;
+       while (curr > 0) {
+               data = cpu_to_be32(curr);
+               err = snd_fw_transaction(dg00x->unit,
+                                        TCODE_WRITE_QUADLET_REQUEST,
+                                        DG00X_ADDR_BASE +
+                                        DG00X_OFFSET_STREAMING_SET,
+                                        &data, sizeof(data), 0);
+               if (err < 0)
+                       goto error;
+
+               msleep(20);
+               curr--;
+       }
+
+       return 0;
+error:
+       finish_session(dg00x);
+       return err;
+}
+
+static void release_resources(struct snd_dg00x *dg00x)
+{
+       __be32 data = 0;
+
+       /* Unregister isochronous channels for both direction. */
+       snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+                          &data, sizeof(data), 0);
+
+       /* Release isochronous resources. */
+       fw_iso_resources_free(&dg00x->tx_resources);
+       fw_iso_resources_free(&dg00x->rx_resources);
+}
+
+static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
+{
+       unsigned int i;
+       __be32 data;
+       int err;
+
+       /* Check sampling rate. */
+       for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
+               if (snd_dg00x_stream_rates[i] == rate)
+                       break;
+       }
+       if (i == SND_DG00X_RATE_COUNT)
+               return -EINVAL;
+
+       /* Keep resources for out-stream. */
+       err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
+                                      snd_dg00x_stream_pcm_channels[i]);
+       if (err < 0)
+               return err;
+       err = fw_iso_resources_allocate(&dg00x->rx_resources,
+                               amdtp_stream_get_max_payload(&dg00x->rx_stream),
+                               fw_parent_device(dg00x->unit)->max_speed);
+       if (err < 0)
+               return err;
+
+       /* Keep resources for in-stream. */
+       err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
+                                      snd_dg00x_stream_pcm_channels[i]);
+       if (err < 0)
+               return err;
+       err = fw_iso_resources_allocate(&dg00x->tx_resources,
+                               amdtp_stream_get_max_payload(&dg00x->tx_stream),
+                               fw_parent_device(dg00x->unit)->max_speed);
+       if (err < 0)
+               goto error;
+
+       /* Register isochronous channels for both direction. */
+       data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
+                          dg00x->rx_resources.channel);
+       err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
+                                &data, sizeof(data), 0);
+       if (err < 0)
+               goto error;
+
+       return 0;
+error:
+       release_resources(dg00x);
+       return err;
+}
+
+int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       /* For out-stream. */
+       err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit);
+       if (err < 0)
+               goto error;
+       err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM);
+       if (err < 0)
+               goto error;
+
+       /* For in-stream. */
+       err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit);
+       if (err < 0)
+               goto error;
+       err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM);
+       if (err < 0)
+               goto error;
+
+       return 0;
+error:
+       snd_dg00x_stream_destroy_duplex(dg00x);
+       return err;
+}
+
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
+void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
+{
+       amdtp_stream_destroy(&dg00x->rx_stream);
+       fw_iso_resources_destroy(&dg00x->rx_resources);
+
+       amdtp_stream_destroy(&dg00x->tx_stream);
+       fw_iso_resources_destroy(&dg00x->tx_resources);
+}
+
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+{
+       unsigned int curr_rate;
+       int err = 0;
+
+       if (dg00x->substreams_counter == 0)
+               goto end;
+
+       /* Check current sampling rate. */
+       err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
+       if (err < 0)
+               goto error;
+       if (rate == 0)
+               rate = curr_rate;
+       if (curr_rate != rate ||
+           amdtp_streaming_error(&dg00x->tx_stream) ||
+           amdtp_streaming_error(&dg00x->rx_stream)) {
+               finish_session(dg00x);
+
+               amdtp_stream_stop(&dg00x->tx_stream);
+               amdtp_stream_stop(&dg00x->rx_stream);
+               release_resources(dg00x);
+       }
+
+       /*
+        * No packets are transmitted without receiving packets, reagardless of
+        * which source of clock is used.
+        */
+       if (!amdtp_stream_running(&dg00x->rx_stream)) {
+               err = snd_dg00x_stream_set_local_rate(dg00x, rate);
+               if (err < 0)
+                       goto error;
+
+               err = keep_resources(dg00x, rate);
+               if (err < 0)
+                       goto error;
+
+               err = begin_session(dg00x);
+               if (err < 0)
+                       goto error;
+
+               err = amdtp_stream_start(&dg00x->rx_stream,
+                               dg00x->rx_resources.channel,
+                               fw_parent_device(dg00x->unit)->max_speed);
+               if (err < 0)
+                       goto error;
+
+               if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
+                                             CALLBACK_TIMEOUT)) {
+                       err = -ETIMEDOUT;
+                       goto error;
+               }
+       }
+
+       /*
+        * The value of SYT field in transmitted packets is always 0x0000. Thus,
+        * duplex streams with timestamp synchronization cannot be built.
+        */
+       if (!amdtp_stream_running(&dg00x->tx_stream)) {
+               err = amdtp_stream_start(&dg00x->tx_stream,
+                               dg00x->tx_resources.channel,
+                               fw_parent_device(dg00x->unit)->max_speed);
+               if (err < 0)
+                       goto error;
+
+               if (!amdtp_stream_wait_callback(&dg00x->tx_stream,
+                                             CALLBACK_TIMEOUT)) {
+                       err = -ETIMEDOUT;
+                       goto error;
+               }
+       }
+end:
+       return err;
+error:
+       finish_session(dg00x);
+
+       amdtp_stream_stop(&dg00x->tx_stream);
+       amdtp_stream_stop(&dg00x->rx_stream);
+       release_resources(dg00x);
+
+       return err;
+}
+
+void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
+{
+       if (dg00x->substreams_counter > 0)
+               return;
+
+       amdtp_stream_stop(&dg00x->tx_stream);
+       amdtp_stream_stop(&dg00x->rx_stream);
+       finish_session(dg00x);
+       release_resources(dg00x);
+
+       /*
+        * Just after finishing the session, the device may lost transmitting
+        * functionality for a short time.
+        */
+       msleep(50);
+}
+
+void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
+{
+       fw_iso_resources_update(&dg00x->tx_resources);
+       fw_iso_resources_update(&dg00x->rx_resources);
+
+       amdtp_stream_update(&dg00x->tx_stream);
+       amdtp_stream_update(&dg00x->rx_stream);
+}
+
+void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
+{
+       dg00x->dev_lock_changed = true;
+       wake_up(&dg00x->hwdep_wait);
+}
+
+int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
+{
+       int err;
+
+       spin_lock_irq(&dg00x->lock);
+
+       /* user land lock this */
+       if (dg00x->dev_lock_count < 0) {
+               err = -EBUSY;
+               goto end;
+       }
+
+       /* this is the first time */
+       if (dg00x->dev_lock_count++ == 0)
+               snd_dg00x_stream_lock_changed(dg00x);
+       err = 0;
+end:
+       spin_unlock_irq(&dg00x->lock);
+       return err;
+}
+
+void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
+{
+       spin_lock_irq(&dg00x->lock);
+
+       if (WARN_ON(dg00x->dev_lock_count <= 0))
+               goto end;
+       if (--dg00x->dev_lock_count == 0)
+               snd_dg00x_stream_lock_changed(dg00x);
+end:
+       spin_unlock_irq(&dg00x->lock);
+}
diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c
new file mode 100644 (file)
index 0000000..554324d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <sound/asound.h>
+#include "digi00x.h"
+
+static int fill_midi_message(struct snd_rawmidi_substream *substream, u8 *buf)
+{
+       int bytes;
+
+       buf[0] = 0x80;
+       bytes = snd_rawmidi_transmit_peek(substream, buf + 1, 2);
+       if (bytes >= 0)
+               buf[3] = 0xc0 | bytes;
+
+       return bytes;
+}
+
+static void handle_midi_control(struct snd_dg00x *dg00x, __be32 *buf,
+                               unsigned int length)
+{
+       struct snd_rawmidi_substream *substream;
+       unsigned int i;
+       unsigned int len;
+       u8 *b;
+
+       substream = ACCESS_ONCE(dg00x->in_control);
+       if (substream == NULL)
+               return;
+
+       length /= 4;
+
+       for (i = 0; i < length; i++) {
+               b = (u8 *)&buf[i];
+               len = b[3] & 0xf;
+               if (len > 0)
+                       snd_rawmidi_receive(dg00x->in_control, b + 1, len);
+       }
+}
+
+static void handle_unknown_message(struct snd_dg00x *dg00x,
+                                  unsigned long long offset, __be32 *buf)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dg00x->lock, flags);
+       dg00x->msg = be32_to_cpu(*buf);
+       spin_unlock_irqrestore(&dg00x->lock, flags);
+
+       wake_up(&dg00x->hwdep_wait);
+}
+
+static void handle_message(struct fw_card *card, struct fw_request *request,
+                          int tcode, int destination, int source,
+                          int generation, unsigned long long offset,
+                          void *data, size_t length, void *callback_data)
+{
+       struct snd_dg00x *dg00x = callback_data;
+       __be32 *buf = (__be32 *)data;
+
+       if (offset == dg00x->async_handler.offset)
+               handle_unknown_message(dg00x, offset, buf);
+       else if (offset == dg00x->async_handler.offset + 4)
+               handle_midi_control(dg00x, buf, length);
+
+       fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x)
+{
+       struct fw_device *device = fw_parent_device(dg00x->unit);
+       __be32 data[2];
+       int err;
+
+       /* Unknown. 4bytes. */
+       data[0] = cpu_to_be32((device->card->node_id << 16) |
+                             (dg00x->async_handler.offset >> 32));
+       data[1] = cpu_to_be32(dg00x->async_handler.offset);
+       err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST,
+                                DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR,
+                                &data, sizeof(data), 0);
+       if (err < 0)
+               return err;
+
+       /* Asynchronous transactions for MIDI control message. */
+       data[0] = cpu_to_be32((device->card->node_id << 16) |
+                             (dg00x->async_handler.offset >> 32));
+       data[1] = cpu_to_be32(dg00x->async_handler.offset + 4);
+       return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST,
+                                 DG00X_ADDR_BASE + DG00X_OFFSET_MIDI_CTL_ADDR,
+                                 &data, sizeof(data), 0);
+}
+
+int snd_dg00x_transaction_register(struct snd_dg00x *dg00x)
+{
+       static const struct fw_address_region resp_register_region = {
+               .start  = 0xffffe0000000ull,
+               .end    = 0xffffe000ffffull,
+       };
+       int err;
+
+       dg00x->async_handler.length = 12;
+       dg00x->async_handler.address_callback = handle_message;
+       dg00x->async_handler.callback_data = dg00x;
+
+       err = fw_core_add_address_handler(&dg00x->async_handler,
+                                         &resp_register_region);
+       if (err < 0)
+               return err;
+
+       err = snd_dg00x_transaction_reregister(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_fw_async_midi_port_init(&dg00x->out_control, dg00x->unit,
+                                         DG00X_ADDR_BASE + DG00X_OFFSET_MMC,
+                                         4, fill_midi_message);
+       if (err < 0)
+               goto error;
+
+       return err;
+error:
+       fw_core_remove_address_handler(&dg00x->async_handler);
+       dg00x->async_handler.address_callback = NULL;
+       return err;
+}
+
+void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x)
+{
+       snd_fw_async_midi_port_destroy(&dg00x->out_control);
+       fw_core_remove_address_handler(&dg00x->async_handler);
+}
diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c
new file mode 100644 (file)
index 0000000..1f33b7a
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * digi00x.c - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "digi00x.h"
+
+MODULE_DESCRIPTION("Digidesign Digi 002/003 family Driver");
+MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
+MODULE_LICENSE("GPL v2");
+
+#define VENDOR_DIGIDESIGN      0x00a07e
+#define MODEL_DIGI00X          0x000002
+
+static int name_card(struct snd_dg00x *dg00x)
+{
+       struct fw_device *fw_dev = fw_parent_device(dg00x->unit);
+       char name[32] = {0};
+       char *model;
+       int err;
+
+       err = fw_csr_string(dg00x->unit->directory, CSR_MODEL, name,
+                           sizeof(name));
+       if (err < 0)
+               return err;
+
+       model = skip_spaces(name);
+
+       strcpy(dg00x->card->driver, "Digi00x");
+       strcpy(dg00x->card->shortname, model);
+       strcpy(dg00x->card->mixername, model);
+       snprintf(dg00x->card->longname, sizeof(dg00x->card->longname),
+                "Digidesign %s, GUID %08x%08x at %s, S%d", model,
+                fw_dev->config_rom[3], fw_dev->config_rom[4],
+                dev_name(&dg00x->unit->device), 100 << fw_dev->max_speed);
+
+       return 0;
+}
+
+static void dg00x_card_free(struct snd_card *card)
+{
+       struct snd_dg00x *dg00x = card->private_data;
+
+       snd_dg00x_stream_destroy_duplex(dg00x);
+       snd_dg00x_transaction_unregister(dg00x);
+
+       fw_unit_put(dg00x->unit);
+
+       mutex_destroy(&dg00x->mutex);
+}
+
+static int snd_dg00x_probe(struct fw_unit *unit,
+                          const struct ieee1394_device_id *entry)
+{
+       struct snd_card *card;
+       struct snd_dg00x *dg00x;
+       int err;
+
+       /* create card */
+       err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+                          sizeof(struct snd_dg00x), &card);
+       if (err < 0)
+               return err;
+       card->private_free = dg00x_card_free;
+
+       /* initialize myself */
+       dg00x = card->private_data;
+       dg00x->card = card;
+       dg00x->unit = fw_unit_get(unit);
+
+       mutex_init(&dg00x->mutex);
+       spin_lock_init(&dg00x->lock);
+       init_waitqueue_head(&dg00x->hwdep_wait);
+
+       err = name_card(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_dg00x_stream_init_duplex(dg00x);
+       if (err < 0)
+               goto error;
+
+       snd_dg00x_proc_init(dg00x);
+
+       err = snd_dg00x_create_pcm_devices(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_dg00x_create_midi_devices(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_dg00x_create_hwdep_device(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_dg00x_transaction_register(dg00x);
+       if (err < 0)
+               goto error;
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dev_set_drvdata(&unit->device, dg00x);
+
+       return err;
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static void snd_dg00x_update(struct fw_unit *unit)
+{
+       struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
+
+       snd_dg00x_transaction_reregister(dg00x);
+
+       mutex_lock(&dg00x->mutex);
+       snd_dg00x_stream_update_duplex(dg00x);
+       mutex_unlock(&dg00x->mutex);
+}
+
+static void snd_dg00x_remove(struct fw_unit *unit)
+{
+       struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
+
+       /* No need to wait for releasing card object in this context. */
+       snd_card_free_when_closed(dg00x->card);
+}
+
+static const struct ieee1394_device_id snd_dg00x_id_table[] = {
+       /* Both of 002/003 use the same ID. */
+       {
+               .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_MODEL_ID,
+               .vendor_id = VENDOR_DIGIDESIGN,
+               .model_id = MODEL_DIGI00X,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(ieee1394, snd_dg00x_id_table);
+
+static struct fw_driver dg00x_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "snd-firewire-digi00x",
+               .bus = &fw_bus_type,
+       },
+       .probe    = snd_dg00x_probe,
+       .update   = snd_dg00x_update,
+       .remove   = snd_dg00x_remove,
+       .id_table = snd_dg00x_id_table,
+};
+
+static int __init snd_dg00x_init(void)
+{
+       return driver_register(&dg00x_driver.driver);
+}
+
+static void __exit snd_dg00x_exit(void)
+{
+       driver_unregister(&dg00x_driver.driver);
+}
+
+module_init(snd_dg00x_init);
+module_exit(snd_dg00x_exit);
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
new file mode 100644 (file)
index 0000000..907e739
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * digi00x.h - a part of driver for Digidesign Digi 002/003 family
+ *
+ * Copyright (c) 2014-2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef SOUND_DIGI00X_H_INCLUDED
+#define SOUND_DIGI00X_H_INCLUDED
+
+#include <linux/compat.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+#include <sound/rawmidi.h>
+
+#include "../lib.h"
+#include "../iso-resources.h"
+#include "../amdtp-stream.h"
+
+struct snd_dg00x {
+       struct snd_card *card;
+       struct fw_unit *unit;
+
+       struct mutex mutex;
+       spinlock_t lock;
+
+       struct amdtp_stream tx_stream;
+       struct fw_iso_resources tx_resources;
+
+       struct amdtp_stream rx_stream;
+       struct fw_iso_resources rx_resources;
+
+       unsigned int substreams_counter;
+
+       /* for uapi */
+       int dev_lock_count;
+       bool dev_lock_changed;
+       wait_queue_head_t hwdep_wait;
+
+       /* For asynchronous messages. */
+       struct fw_address_handler async_handler;
+       u32 msg;
+
+       /* For asynchronous MIDI controls. */
+       struct snd_rawmidi_substream *in_control;
+       struct snd_fw_async_midi_port out_control;
+};
+
+#define DG00X_ADDR_BASE                0xffffe0000000ull
+
+#define DG00X_OFFSET_STREAMING_STATE   0x0000
+#define DG00X_OFFSET_STREAMING_SET     0x0004
+#define DG00X_OFFSET_MIDI_CTL_ADDR     0x0008
+/* For LSB of the address              0x000c */
+/* unknown                             0x0010 */
+#define DG00X_OFFSET_MESSAGE_ADDR      0x0014
+/* For LSB of the address              0x0018 */
+/* unknown                             0x001c */
+/* unknown                             0x0020 */
+/* not used                    0x0024--0x00ff */
+#define DG00X_OFFSET_ISOC_CHANNELS     0x0100
+/* unknown                             0x0104 */
+/* unknown                             0x0108 */
+/* unknown                             0x010c */
+#define DG00X_OFFSET_LOCAL_RATE                0x0110
+#define DG00X_OFFSET_EXTERNAL_RATE     0x0114
+#define DG00X_OFFSET_CLOCK_SOURCE      0x0118
+#define DG00X_OFFSET_OPT_IFACE_MODE    0x011c
+/* unknown                             0x0120 */
+/* Mixer control on/off                        0x0124 */
+/* unknown                             0x0128 */
+#define DG00X_OFFSET_DETECT_EXTERNAL   0x012c
+/* unknown                             0x0138 */
+#define DG00X_OFFSET_MMC               0x0400
+
+enum snd_dg00x_rate {
+       SND_DG00X_RATE_44100 = 0,
+       SND_DG00X_RATE_48000,
+       SND_DG00X_RATE_88200,
+       SND_DG00X_RATE_96000,
+       SND_DG00X_RATE_COUNT,
+};
+
+enum snd_dg00x_clock {
+       SND_DG00X_CLOCK_INTERNAL = 0,
+       SND_DG00X_CLOCK_SPDIF,
+       SND_DG00X_CLOCK_ADAT,
+       SND_DG00X_CLOCK_WORD,
+       SND_DG00X_CLOCK_COUNT,
+};
+
+enum snd_dg00x_optical_mode {
+       SND_DG00X_OPT_IFACE_MODE_ADAT = 0,
+       SND_DG00X_OPT_IFACE_MODE_SPDIF,
+       SND_DG00X_OPT_IFACE_MODE_COUNT,
+};
+
+#define DOT_MIDI_IN_PORTS      1
+#define DOT_MIDI_OUT_PORTS     2
+
+int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
+                  enum amdtp_stream_direction dir);
+int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
+                            unsigned int pcm_channels);
+void amdtp_dot_reset(struct amdtp_stream *s);
+int amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                    struct snd_pcm_runtime *runtime);
+void amdtp_dot_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format);
+void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port,
+                         struct snd_rawmidi_substream *midi);
+
+int snd_dg00x_transaction_register(struct snd_dg00x *dg00x);
+int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x);
+void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x);
+
+extern const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT];
+extern const unsigned int snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT];
+int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
+                                      unsigned int *rate);
+int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x,
+                                   unsigned int *rate);
+int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
+                              enum snd_dg00x_clock *clock);
+int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
+                                         bool *detect);
+int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
+void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
+void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);
+
+void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x);
+int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x);
+void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x);
+
+void snd_dg00x_proc_init(struct snd_dg00x *dg00x);
+
+int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x);
+
+int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x);
+
+int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x);
+#endif
index 0619597e3a3f250b5e5b40d07d6c0e68de1a8ccb..cce19768f43d0a3f32c9d3c0187c1077f5bbfeab 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/delay.h>
 #include "fcp.h"
 #include "lib.h"
-#include "amdtp.h"
+#include "amdtp-stream.h"
 
 #define CTS_AVC 0x00
 
index 0c7440826db8e5b7f2e21d087da6fc0cc8ea50f4..15ef7f75a8ef123b5ee335fa4dcd4bef6c3c9122 100644 (file)
@@ -1,4 +1,4 @@
 snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \
                      fireworks_stream.o fireworks_proc.o fireworks_midi.o \
                      fireworks_pcm.o fireworks_hwdep.o fireworks.o
-obj-m += snd-fireworks.o
+obj-$(CONFIG_SND_FIREWORKS) += snd-fireworks.o
index c94a432f7cc653dca45316ea67bdc481b9e8e887..d5b19bc11e5999480f030e682fa4087cc91067ac 100644 (file)
@@ -138,12 +138,12 @@ get_hardware_info(struct snd_efw *efw)
        efw->midi_out_ports = hwinfo->midi_out_ports;
        efw->midi_in_ports = hwinfo->midi_in_ports;
 
-       if (hwinfo->amdtp_tx_pcm_channels    > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           hwinfo->amdtp_tx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           hwinfo->amdtp_tx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           hwinfo->amdtp_rx_pcm_channels    > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           hwinfo->amdtp_rx_pcm_channels_2x > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           hwinfo->amdtp_rx_pcm_channels_4x > AMDTP_MAX_CHANNELS_FOR_PCM) {
+       if (hwinfo->amdtp_tx_pcm_channels    > AM824_MAX_CHANNELS_FOR_PCM ||
+           hwinfo->amdtp_tx_pcm_channels_2x > AM824_MAX_CHANNELS_FOR_PCM ||
+           hwinfo->amdtp_tx_pcm_channels_4x > AM824_MAX_CHANNELS_FOR_PCM ||
+           hwinfo->amdtp_rx_pcm_channels    > AM824_MAX_CHANNELS_FOR_PCM ||
+           hwinfo->amdtp_rx_pcm_channels_2x > AM824_MAX_CHANNELS_FOR_PCM ||
+           hwinfo->amdtp_rx_pcm_channels_4x > AM824_MAX_CHANNELS_FOR_PCM) {
                err = -ENOSYS;
                goto end;
        }
index 084d414b228cf425dc99440cc081d65459bbe175..c7cb7deafe48487fd802fbf5ce84e34c2f5ab2eb 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "../packets-buffer.h"
 #include "../iso-resources.h"
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../cmp.h"
 #include "../lib.h"
 
index 166f80584c2a923da199990ca0b1920f646e52a0..94bab0476a65ce69011aaad0bf1ac8eac8a60e76 100644 (file)
@@ -257,7 +257,7 @@ int snd_efw_command_get_phys_meters(struct snd_efw *efw,
                                    struct snd_efw_phys_meters *meters,
                                    unsigned int len)
 {
-       __be32 *buf = (__be32 *)meters;
+       u32 *buf = (u32 *)meters;
        unsigned int i;
        int err;
 
index cf9c6526043938aa905019c23992fdf496247403..fba01bbba4564be493af246a3d40957da2c1465d 100644 (file)
@@ -73,10 +73,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&efw->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&efw->tx_stream,
+               amdtp_am824_midi_trigger(&efw->tx_stream,
                                          substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&efw->tx_stream,
+               amdtp_am824_midi_trigger(&efw->tx_stream,
                                          substrm->number, NULL);
 
        spin_unlock_irqrestore(&efw->lock, flags);
@@ -90,11 +90,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&efw->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&efw->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&efw->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&efw->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&efw->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&efw->lock, flags);
 }
index c30b2ffa8dfb1db8354c25b4681938ac82627194..d27135bac5133e5d57bf5444e06f1e105559932e 100644 (file)
@@ -159,11 +159,11 @@ pcm_init_hw_params(struct snd_efw *efw,
                           SNDRV_PCM_INFO_MMAP_VALID;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
                s = &efw->tx_stream;
                pcm_channels = efw->pcm_capture_channels;
        } else {
-               runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
                s = &efw->rx_stream;
                pcm_channels = efw->pcm_playback_channels;
        }
@@ -187,7 +187,7 @@ pcm_init_hw_params(struct snd_efw *efw,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
 end:
        return err;
 }
@@ -253,7 +253,8 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&efw->capture_substreams);
-       amdtp_stream_set_pcm_format(&efw->tx_stream, params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -270,7 +271,8 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
                atomic_inc(&efw->playback_substreams);
-       amdtp_stream_set_pcm_format(&efw->rx_stream, params_format(hw_params));
+
+       amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 7e353f1f7bff359ea8845630aeff2521759e508f..759f6e3ed44ab08fb8d480b63dacf135ca734bab 100644 (file)
@@ -31,7 +31,7 @@ init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_init(stream, efw->unit, s_dir, CIP_BLOCKING);
+       err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(stream);
                cmp_connection_destroy(conn);
@@ -73,8 +73,10 @@ start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
                midi_ports = efw->midi_in_ports;
        }
 
-       amdtp_stream_set_parameters(stream, sampling_rate,
-                                   pcm_channels, midi_ports);
+       err = amdtp_am824_set_parameters(stream, sampling_rate,
+                                        pcm_channels, midi_ports, false);
+       if (err < 0)
+               goto end;
 
        /*  establish connection via CMP */
        err = cmp_connection_establish(conn,
index 7409edba9f06761b11d8582bd60fb43bcc8a0ff6..f80aafa44c89499ff92b0b3af0bc761ca49c0567 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/device.h>
 #include <linux/firewire.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "lib.h"
 
 #define ERROR_RETRY_DELAY_MS   20
@@ -66,6 +67,147 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode,
 }
 EXPORT_SYMBOL(snd_fw_transaction);
 
+static void async_midi_port_callback(struct fw_card *card, int rcode,
+                                    void *data, size_t length,
+                                    void *callback_data)
+{
+       struct snd_fw_async_midi_port *port = callback_data;
+       struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+
+       /* This port is closed. */
+       if (substream == NULL)
+               return;
+
+       if (rcode == RCODE_COMPLETE)
+               snd_rawmidi_transmit_ack(substream, port->consume_bytes);
+       else if (!rcode_is_permanent_error(rcode))
+               /* To start next transaction immediately for recovery. */
+               port->next_ktime = ktime_set(0, 0);
+       else
+               /* Don't continue processing. */
+               port->error = true;
+
+       port->idling = true;
+
+       if (!snd_rawmidi_transmit_empty(substream))
+               schedule_work(&port->work);
+}
+
+static void midi_port_work(struct work_struct *work)
+{
+       struct snd_fw_async_midi_port *port =
+                       container_of(work, struct snd_fw_async_midi_port, work);
+       struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+       int generation;
+       int type;
+
+       /* Under transacting or error state. */
+       if (!port->idling || port->error)
+               return;
+
+       /* Nothing to do. */
+       if (substream == NULL || snd_rawmidi_transmit_empty(substream))
+               return;
+
+       /* Do it in next chance. */
+       if (ktime_after(port->next_ktime, ktime_get())) {
+               schedule_work(&port->work);
+               return;
+       }
+
+       /*
+        * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
+        * Later, snd_rawmidi_transmit_ack() is called.
+        */
+       memset(port->buf, 0, port->len);
+       port->consume_bytes = port->fill(substream, port->buf);
+       if (port->consume_bytes <= 0) {
+               /* Do it in next chance, immediately. */
+               if (port->consume_bytes == 0) {
+                       port->next_ktime = ktime_set(0, 0);
+                       schedule_work(&port->work);
+               } else {
+                       /* Fatal error. */
+                       port->error = true;
+               }
+               return;
+       }
+
+       /* Calculate type of transaction. */
+       if (port->len == 4)
+               type = TCODE_WRITE_QUADLET_REQUEST;
+       else
+               type = TCODE_WRITE_BLOCK_REQUEST;
+
+       /* Set interval to next transaction. */
+       port->next_ktime = ktime_add_ns(ktime_get(),
+                               port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
+
+       /* Start this transaction. */
+       port->idling = false;
+
+       /*
+        * In Linux FireWire core, when generation is updated with memory
+        * barrier, node id has already been updated. In this module, After
+        * this smp_rmb(), load/store instructions to memory are completed.
+        * Thus, both of generation and node id are available with recent
+        * values. This is a light-serialization solution to handle bus reset
+        * events on IEEE 1394 bus.
+        */
+       generation = port->parent->generation;
+       smp_rmb();
+
+       fw_send_request(port->parent->card, &port->transaction, type,
+                       port->parent->node_id, generation,
+                       port->parent->max_speed, port->addr,
+                       port->buf, port->len, async_midi_port_callback,
+                       port);
+}
+
+/**
+ * snd_fw_async_midi_port_init - initialize asynchronous MIDI port structure
+ * @port: the asynchronous MIDI port to initialize
+ * @unit: the target of the asynchronous transaction
+ * @addr: the address to which transactions are transferred
+ * @len: the length of transaction
+ * @fill: the callback function to fill given buffer, and returns the
+ *            number of consumed bytes for MIDI message.
+ *
+ */
+int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
+               struct fw_unit *unit, u64 addr, unsigned int len,
+               snd_fw_async_midi_port_fill fill)
+{
+       port->len = DIV_ROUND_UP(len, 4) * 4;
+       port->buf = kzalloc(port->len, GFP_KERNEL);
+       if (port->buf == NULL)
+               return -ENOMEM;
+
+       port->parent = fw_parent_device(unit);
+       port->addr = addr;
+       port->fill = fill;
+       port->idling = true;
+       port->next_ktime = ktime_set(0, 0);
+       port->error = false;
+
+       INIT_WORK(&port->work, midi_port_work);
+
+       return 0;
+}
+EXPORT_SYMBOL(snd_fw_async_midi_port_init);
+
+/**
+ * snd_fw_async_midi_port_destroy - free asynchronous MIDI port structure
+ * @port: the asynchronous MIDI port structure
+ */
+void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port)
+{
+       snd_fw_async_midi_port_finish(port);
+       cancel_work_sync(&port->work);
+       kfree(port->buf);
+}
+EXPORT_SYMBOL(snd_fw_async_midi_port_destroy);
+
 MODULE_DESCRIPTION("FireWire audio helper functions");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
index 02cfabc9c3c4ba53d18e7b827600491fd9c2df84..f3f6f84c48d69747cc0fa3bd815d986c79ca0d78 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <linux/firewire-constants.h>
 #include <linux/types.h>
+#include <linux/sched.h>
+#include <sound/rawmidi.h>
 
 struct fw_unit;
 
@@ -20,4 +22,58 @@ static inline bool rcode_is_permanent_error(int rcode)
        return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR;
 }
 
+struct snd_fw_async_midi_port;
+typedef int (*snd_fw_async_midi_port_fill)(
+                               struct snd_rawmidi_substream *substream,
+                               u8 *buf);
+
+struct snd_fw_async_midi_port {
+       struct fw_device *parent;
+       struct work_struct work;
+       bool idling;
+       ktime_t next_ktime;
+       bool error;
+
+       u64 addr;
+       struct fw_transaction transaction;
+
+       u8 *buf;
+       unsigned int len;
+
+       struct snd_rawmidi_substream *substream;
+       snd_fw_async_midi_port_fill fill;
+       unsigned int consume_bytes;
+};
+
+int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
+               struct fw_unit *unit, u64 addr, unsigned int len,
+               snd_fw_async_midi_port_fill fill);
+void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port);
+
+/**
+ * snd_fw_async_midi_port_run - run transactions for the async MIDI port
+ * @port: the asynchronous MIDI port
+ * @substream: the MIDI substream
+ */
+static inline void
+snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
+                          struct snd_rawmidi_substream *substream)
+{
+       if (!port->error) {
+               port->substream = substream;
+               schedule_work(&port->work);
+       }
+}
+
+/**
+ * snd_fw_async_midi_port_finish - finish the asynchronous MIDI port
+ * @port: the asynchronous MIDI port
+ */
+static inline void
+snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
+{
+       port->substream = NULL;
+       port->error = false;
+}
+
 #endif
index a926850864f6706e45b3245d02c8962ddcd7647c..06ff50f4e6c0b19826caabbfcbd28998927a8929 100644 (file)
@@ -1,3 +1,3 @@
 snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
                 oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o
-obj-m += snd-oxfw.o
+obj-$(CONFIG_SND_OXFW) += snd-oxfw.o
index 540a303385169d011a3813aaa8483d7d8b67bbe0..8665e1043d41fa380a8a94f213098cbca29d87ef 100644 (file)
@@ -90,11 +90,11 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&oxfw->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&oxfw->tx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&oxfw->tx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&oxfw->tx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&oxfw->tx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&oxfw->lock, flags);
 }
@@ -107,11 +107,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_lock_irqsave(&oxfw->lock, flags);
 
        if (up)
-               amdtp_stream_midi_trigger(&oxfw->rx_stream,
-                                         substrm->number, substrm);
+               amdtp_am824_midi_trigger(&oxfw->rx_stream,
+                                        substrm->number, substrm);
        else
-               amdtp_stream_midi_trigger(&oxfw->rx_stream,
-                                         substrm->number, NULL);
+               amdtp_am824_midi_trigger(&oxfw->rx_stream,
+                                        substrm->number, NULL);
 
        spin_unlock_irqrestore(&oxfw->lock, flags);
 }
@@ -142,29 +142,11 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
 
 int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
 {
-       struct snd_oxfw_stream_formation formation;
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *str;
-       u8 *format;
-       int i, err;
-
-       /* If its stream has MIDI conformant data channel, add one MIDI port */
-       for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
-               format = oxfw->tx_stream_formats[i];
-               if (format != NULL) {
-                       err = snd_oxfw_stream_parse_format(format, &formation);
-                       if (err >= 0 && formation.midi > 0)
-                               oxfw->midi_input_ports = 1;
-               }
-
-               format = oxfw->rx_stream_formats[i];
-               if (format != NULL) {
-                       err = snd_oxfw_stream_parse_format(format, &formation);
-                       if (err >= 0 && formation.midi > 0)
-                               oxfw->midi_output_ports = 1;
-               }
-       }
-       if ((oxfw->midi_input_ports == 0) && (oxfw->midi_output_ports == 0))
+       int err;
+
+       if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
                return 0;
 
        /* create midi ports */
index 9c73930d0278820a11fd46a2db2fb877b6a61a88..8d233417695d613141c2a49f44c279fc0b57b45e 100644 (file)
@@ -134,11 +134,11 @@ static int init_hw_params(struct snd_oxfw *oxfw,
                           SNDRV_PCM_INFO_MMAP_VALID;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
                stream = &oxfw->tx_stream;
                formats = oxfw->tx_stream_formats;
        } else {
-               runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+               runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
                stream = &oxfw->rx_stream;
                formats = oxfw->rx_stream_formats;
        }
@@ -158,7 +158,7 @@ static int init_hw_params(struct snd_oxfw *oxfw,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+       err = amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 end:
        return err;
 }
@@ -244,7 +244,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&oxfw->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
+       amdtp_am824_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
 
        return 0;
 }
@@ -265,7 +265,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
                mutex_unlock(&oxfw->mutex);
        }
 
-       amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
+       amdtp_am824_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
 
        return 0;
 }
index 77ad5b98e806fa694ddd5c0a4c2ae439c78aebf8..7cb5743c073bbed3f88d2452b6b6a7047f7619f3 100644 (file)
@@ -148,14 +148,17 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
        }
 
        pcm_channels = formation.pcm;
-       midi_ports = DIV_ROUND_UP(formation.midi, 8);
+       midi_ports = formation.midi * 8;
 
        /* The stream should have one pcm channels at least */
        if (pcm_channels == 0) {
                err = -EINVAL;
                goto end;
        }
-       amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
+       err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports,
+                                        false);
+       if (err < 0)
+               goto end;
 
        err = cmp_connection_establish(conn,
                                       amdtp_stream_get_max_payload(stream));
@@ -225,7 +228,7 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
        if (err < 0)
                goto end;
 
-       err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
+       err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
        if (err < 0) {
                amdtp_stream_destroy(stream);
                cmp_connection_destroy(conn);
@@ -238,9 +241,12 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
         * packets. As a result, next isochronous packet includes more data
         * blocks than IEC 61883-6 defines.
         */
-       if (stream == &oxfw->tx_stream)
+       if (stream == &oxfw->tx_stream) {
                oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK |
                                         CIP_JUMBO_PAYLOAD;
+               if (oxfw->wrong_dbs)
+                       oxfw->tx_stream.flags |= CIP_WRONG_DBS;
+       }
 end:
        return err;
 }
@@ -480,8 +486,8 @@ int snd_oxfw_stream_parse_format(u8 *format,
                }
        }
 
-       if (formation->pcm  > AMDTP_MAX_CHANNELS_FOR_PCM ||
-           formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
+       if (formation->pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
+           formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
                return -ENOSYS;
 
        return 0;
@@ -623,6 +629,9 @@ end:
 int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
 {
        u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
+       struct snd_oxfw_stream_formation formation;
+       u8 *format;
+       unsigned int i;
        int err;
 
        /* the number of plugs for isoc in/out, ext in/out  */
@@ -642,12 +651,42 @@ int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
                err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
                if (err < 0)
                        goto end;
+
+               for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+                       format = oxfw->tx_stream_formats[i];
+                       if (format == NULL)
+                               continue;
+                       err = snd_oxfw_stream_parse_format(format, &formation);
+                       if (err < 0)
+                               continue;
+
+                       /* Add one MIDI port. */
+                       if (formation.midi > 0)
+                               oxfw->midi_input_ports = 1;
+               }
+
                oxfw->has_output = true;
        }
 
        /* use iPCR[0] if exists */
-       if (plugs[0] > 0)
+       if (plugs[0] > 0) {
                err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
+               if (err < 0)
+                       goto end;
+
+               for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+                       format = oxfw->rx_stream_formats[i];
+                       if (format == NULL)
+                               continue;
+                       err = snd_oxfw_stream_parse_format(format, &formation);
+                       if (err < 0)
+                               continue;
+
+                       /* Add one MIDI port. */
+                       if (formation.midi > 0)
+                               oxfw->midi_output_ports = 1;
+               }
+       }
 end:
        return err;
 }
index 8c6ce019f437c310043a3686b634def68c92e424..588b93f20c2e23e6955ca76c5d0b5076561b6fd5 100644 (file)
@@ -18,6 +18,9 @@
 #define VENDOR_GRIFFIN         0x001292
 #define VENDOR_BEHRINGER       0x001564
 #define VENDOR_LACIE           0x00d04b
+#define VENDOR_TASCAM          0x00022e
+
+#define MODEL_SATELLITE                0x00200f
 
 #define SPECIFIER_1394TA       0x00a02d
 #define VERSION_AVC            0x010001
@@ -129,6 +132,40 @@ static void oxfw_card_free(struct snd_card *card)
        mutex_destroy(&oxfw->mutex);
 }
 
+static void detect_quirks(struct snd_oxfw *oxfw)
+{
+       struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
+       struct fw_csr_iterator it;
+       int key, val;
+       int vendor, model;
+
+       /* Seek from Root Directory of Config ROM. */
+       vendor = model = 0;
+       fw_csr_iterator_init(&it, fw_dev->config_rom + 5);
+       while (fw_csr_iterator_next(&it, &key, &val)) {
+               if (key == CSR_VENDOR)
+                       vendor = val;
+               else if (key == CSR_MODEL)
+                       model = val;
+       }
+
+       /*
+        * Mackie Onyx Satellite with base station has a quirk to report a wrong
+        * value in 'dbs' field of CIP header against its format information.
+        */
+       if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE)
+               oxfw->wrong_dbs = true;
+
+       /*
+        * TASCAM FireOne has physical control and requires a pair of additional
+        * MIDI ports.
+        */
+       if (vendor == VENDOR_TASCAM) {
+               oxfw->midi_input_ports++;
+               oxfw->midi_output_ports++;
+       }
+}
+
 static int oxfw_probe(struct fw_unit *unit,
                       const struct ieee1394_device_id *id)
 {
@@ -157,6 +194,8 @@ static int oxfw_probe(struct fw_unit *unit,
        if (err < 0)
                goto error;
 
+       detect_quirks(oxfw);
+
        err = name_card(oxfw);
        if (err < 0)
                goto error;
@@ -294,6 +333,13 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
                .specifier_id   = SPECIFIER_1394TA,
                .version        = VERSION_AVC,
        },
+       /* TASCAM, FireOne */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = VENDOR_TASCAM,
+               .model_id       = 0x800007,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
index cace5ad4fe76134a0fb4ece9a27f2c321021d998..8392c424ad1d53bb91ea04f7dc78f67362b2f543 100644 (file)
@@ -28,7 +28,7 @@
 #include "../fcp.h"
 #include "../packets-buffer.h"
 #include "../iso-resources.h"
-#include "../amdtp.h"
+#include "../amdtp-am824.h"
 #include "../cmp.h"
 
 struct device_info {
@@ -49,6 +49,7 @@ struct snd_oxfw {
        struct mutex mutex;
        spinlock_t lock;
 
+       bool wrong_dbs;
        bool has_output;
        u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
        u8 *rx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
diff --git a/sound/firewire/tascam/Makefile b/sound/firewire/tascam/Makefile
new file mode 100644 (file)
index 0000000..0fc955d
--- /dev/null
@@ -0,0 +1,4 @@
+snd-firewire-tascam-objs := tascam-proc.o amdtp-tascam.o tascam-stream.o \
+                           tascam-pcm.o tascam-hwdep.o tascam-transaction.o \
+                           tascam-midi.o tascam.o
+obj-$(CONFIG_SND_FIREWIRE_TASCAM) += snd-firewire-tascam.o
diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
new file mode 100644 (file)
index 0000000..9dd0fcc
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * amdtp-tascam.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <sound/pcm.h>
+#include "tascam.h"
+
+#define AMDTP_FMT_TSCM_TX      0x1e
+#define AMDTP_FMT_TSCM_RX      0x3e
+
+struct amdtp_tscm {
+       unsigned int pcm_channels;
+
+       void (*transfer_samples)(struct amdtp_stream *s,
+                                struct snd_pcm_substream *pcm,
+                                __be32 *buffer, unsigned int frames);
+};
+
+int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate)
+{
+       struct amdtp_tscm *p = s->protocol;
+       unsigned int data_channels;
+
+       if (amdtp_stream_running(s))
+               return -EBUSY;
+
+       data_channels = p->pcm_channels;
+
+       /* Packets in in-stream have extra 2 data channels. */
+       if (s->direction == AMDTP_IN_STREAM)
+               data_channels += 2;
+
+       return amdtp_stream_set_parameters(s, rate, data_channels);
+}
+
+static void write_pcm_s32(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_tscm *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u32 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32(*src);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_s16(struct amdtp_stream *s,
+                         struct snd_pcm_substream *pcm,
+                         __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_tscm *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       const u16 *src;
+
+       channels = p->pcm_channels;
+       src = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       buffer[c] = cpu_to_be32(*src << 16);
+                       src++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       src = (void *)runtime->dma_area;
+       }
+}
+
+static void read_pcm_s32(struct amdtp_stream *s,
+                        struct snd_pcm_substream *pcm,
+                        __be32 *buffer, unsigned int frames)
+{
+       struct amdtp_tscm *p = s->protocol;
+       struct snd_pcm_runtime *runtime = pcm->runtime;
+       unsigned int channels, remaining_frames, i, c;
+       u32 *dst;
+
+       channels = p->pcm_channels;
+       dst  = (void *)runtime->dma_area +
+                       frames_to_bytes(runtime, s->pcm_buffer_pointer);
+       remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+       /* The first data channel is for event counter. */
+       buffer += 1;
+
+       for (i = 0; i < frames; ++i) {
+               for (c = 0; c < channels; ++c) {
+                       *dst = be32_to_cpu(buffer[c]);
+                       dst++;
+               }
+               buffer += s->data_block_quadlets;
+               if (--remaining_frames == 0)
+                       dst = (void *)runtime->dma_area;
+       }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
+                             unsigned int data_blocks)
+{
+       struct amdtp_tscm *p = s->protocol;
+       unsigned int channels, i, c;
+
+       channels = p->pcm_channels;
+
+       for (i = 0; i < data_blocks; ++i) {
+               for (c = 0; c < channels; ++c)
+                       buffer[c] = 0x00000000;
+               buffer += s->data_block_quadlets;
+       }
+}
+
+int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                     struct snd_pcm_runtime *runtime)
+{
+       int err;
+
+       /*
+        * Our implementation allows this protocol to deliver 24 bit sample in
+        * 32bit data channel.
+        */
+       err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+       if (err < 0)
+               return err;
+
+       return amdtp_stream_add_pcm_hw_constraints(s, runtime);
+}
+
+void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
+{
+       struct amdtp_tscm *p = s->protocol;
+
+       if (WARN_ON(amdtp_stream_pcm_running(s)))
+               return;
+
+       switch (format) {
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S16:
+               if (s->direction == AMDTP_OUT_STREAM) {
+                       p->transfer_samples = write_pcm_s16;
+                       break;
+               }
+               WARN_ON(1);
+               /* fall through */
+       case SNDRV_PCM_FORMAT_S32:
+               if (s->direction == AMDTP_OUT_STREAM)
+                       p->transfer_samples = write_pcm_s32;
+               else
+                       p->transfer_samples = read_pcm_s32;
+               break;
+       }
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol;
+       struct snd_pcm_substream *pcm;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (data_blocks > 0 && pcm)
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+
+       /* A place holder for control messages. */
+
+       return data_blocks;
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
+                                          __be32 *buffer,
+                                          unsigned int data_blocks,
+                                          unsigned int *syt)
+{
+       struct amdtp_tscm *p = (struct amdtp_tscm *)s->protocol;
+       struct snd_pcm_substream *pcm;
+
+       /* This field is not used. */
+       *syt = 0x0000;
+
+       pcm = ACCESS_ONCE(s->pcm);
+       if (pcm)
+               p->transfer_samples(s, pcm, buffer, data_blocks);
+       else
+               write_pcm_silence(s, buffer, data_blocks);
+
+       return data_blocks;
+}
+
+int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
+                   enum amdtp_stream_direction dir, unsigned int pcm_channels)
+{
+       amdtp_stream_process_data_blocks_t process_data_blocks;
+       struct amdtp_tscm *p;
+       unsigned int fmt;
+       int err;
+
+       if (dir == AMDTP_IN_STREAM) {
+               fmt = AMDTP_FMT_TSCM_TX;
+               process_data_blocks = process_tx_data_blocks;
+       } else {
+               fmt = AMDTP_FMT_TSCM_RX;
+               process_data_blocks = process_rx_data_blocks;
+       }
+
+       err = amdtp_stream_init(s, unit, dir,
+                               CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt,
+                               process_data_blocks, sizeof(struct amdtp_tscm));
+       if (err < 0)
+               return 0;
+
+       /* Use fixed value for FDF field. */
+       s->fdf = 0x00;
+
+       /* This protocol uses fixed number of data channels for PCM samples. */
+       p = s->protocol;
+       p->pcm_channels = pcm_channels;
+
+       return 0;
+}
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
new file mode 100644 (file)
index 0000000..131267c
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * tascam-hwdep.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes give three functionality.
+ *
+ * 1.get firewire node information
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock stream
+ */
+
+#include "tascam.h"
+
+static long hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
+                             long count)
+{
+       union snd_firewire_event event;
+
+       memset(&event, 0, sizeof(event));
+
+       event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+       event.lock_status.status = (tscm->dev_lock_count > 0);
+       tscm->dev_lock_changed = false;
+
+       count = min_t(long, count, sizeof(event.lock_status));
+
+       if (copy_to_user(buf, &event, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
+                      loff_t *offset)
+{
+       struct snd_tscm *tscm = hwdep->private_data;
+       DEFINE_WAIT(wait);
+       union snd_firewire_event event;
+
+       spin_lock_irq(&tscm->lock);
+
+       while (!tscm->dev_lock_changed) {
+               prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+               spin_unlock_irq(&tscm->lock);
+               schedule();
+               finish_wait(&tscm->hwdep_wait, &wait);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               spin_lock_irq(&tscm->lock);
+       }
+
+       memset(&event, 0, sizeof(event));
+       count = hwdep_read_locked(tscm, buf, count);
+       spin_unlock_irq(&tscm->lock);
+
+       return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+                              poll_table *wait)
+{
+       struct snd_tscm *tscm = hwdep->private_data;
+       unsigned int events;
+
+       poll_wait(file, &tscm->hwdep_wait, wait);
+
+       spin_lock_irq(&tscm->lock);
+       if (tscm->dev_lock_changed)
+               events = POLLIN | POLLRDNORM;
+       else
+               events = 0;
+       spin_unlock_irq(&tscm->lock);
+
+       return events;
+}
+
+static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg)
+{
+       struct fw_device *dev = fw_parent_device(tscm->unit);
+       struct snd_firewire_get_info info;
+
+       memset(&info, 0, sizeof(info));
+       info.type = SNDRV_FIREWIRE_TYPE_TASCAM;
+       info.card = dev->card->index;
+       *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+       *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+       strlcpy(info.device_name, dev_name(&dev->device),
+               sizeof(info.device_name));
+
+       if (copy_to_user(arg, &info, sizeof(info)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int hwdep_lock(struct snd_tscm *tscm)
+{
+       int err;
+
+       spin_lock_irq(&tscm->lock);
+
+       if (tscm->dev_lock_count == 0) {
+               tscm->dev_lock_count = -1;
+               err = 0;
+       } else {
+               err = -EBUSY;
+       }
+
+       spin_unlock_irq(&tscm->lock);
+
+       return err;
+}
+
+static int hwdep_unlock(struct snd_tscm *tscm)
+{
+       int err;
+
+       spin_lock_irq(&tscm->lock);
+
+       if (tscm->dev_lock_count == -1) {
+               tscm->dev_lock_count = 0;
+               err = 0;
+       } else {
+               err = -EBADFD;
+       }
+
+       spin_unlock_irq(&tscm->lock);
+
+       return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+       struct snd_tscm *tscm = hwdep->private_data;
+
+       spin_lock_irq(&tscm->lock);
+       if (tscm->dev_lock_count == -1)
+               tscm->dev_lock_count = 0;
+       spin_unlock_irq(&tscm->lock);
+
+       return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+           unsigned int cmd, unsigned long arg)
+{
+       struct snd_tscm *tscm = hwdep->private_data;
+
+       switch (cmd) {
+       case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+               return hwdep_get_info(tscm, (void __user *)arg);
+       case SNDRV_FIREWIRE_IOCTL_LOCK:
+               return hwdep_lock(tscm);
+       case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+               return hwdep_unlock(tscm);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+                             unsigned int cmd, unsigned long arg)
+{
+       return hwdep_ioctl(hwdep, file, cmd,
+                          (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+static const struct snd_hwdep_ops hwdep_ops = {
+       .read           = hwdep_read,
+       .release        = hwdep_release,
+       .poll           = hwdep_poll,
+       .ioctl          = hwdep_ioctl,
+       .ioctl_compat   = hwdep_compat_ioctl,
+};
+
+int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
+{
+       struct snd_hwdep *hwdep;
+       int err;
+
+       err = snd_hwdep_new(tscm->card, "Tascam", 0, &hwdep);
+       if (err < 0)
+               return err;
+
+       strcpy(hwdep->name, "Tascam");
+       hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
+       hwdep->ops = hwdep_ops;
+       hwdep->private_data = tscm;
+       hwdep->exclusive = true;
+
+       return err;
+}
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c
new file mode 100644 (file)
index 0000000..41f8420
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * tascam-midi.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "tascam.h"
+
+static int midi_capture_open(struct snd_rawmidi_substream *substream)
+{
+       /* Do nothing. */
+       return 0;
+}
+
+static int midi_playback_open(struct snd_rawmidi_substream *substream)
+{
+       struct snd_tscm *tscm = substream->rmidi->private_data;
+
+       /* Initialize internal status. */
+       tscm->running_status[substream->number] = 0;
+       tscm->on_sysex[substream->number] = 0;
+       return 0;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *substream)
+{
+       /* Do nothing. */
+       return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *substream)
+{
+       struct snd_tscm *tscm = substream->rmidi->private_data;
+
+       snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]);
+
+       return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+       struct snd_tscm *tscm = substrm->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tscm->lock, flags);
+
+       if (up)
+               tscm->tx_midi_substreams[substrm->number] = substrm;
+       else
+               tscm->tx_midi_substreams[substrm->number] = NULL;
+
+       spin_unlock_irqrestore(&tscm->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+       struct snd_tscm *tscm = substrm->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tscm->lock, flags);
+
+       if (up)
+               snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number],
+                                          substrm);
+
+       spin_unlock_irqrestore(&tscm->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+       .open           = midi_capture_open,
+       .close          = midi_capture_close,
+       .trigger        = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+       .open           = midi_playback_open,
+       .close          = midi_playback_close,
+       .trigger        = midi_playback_trigger,
+};
+
+int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
+{
+       struct snd_rawmidi *rmidi;
+       struct snd_rawmidi_str *stream;
+       struct snd_rawmidi_substream *subs;
+       int err;
+
+       err = snd_rawmidi_new(tscm->card, tscm->card->driver, 0,
+                             tscm->spec->midi_playback_ports,
+                             tscm->spec->midi_capture_ports,
+                             &rmidi);
+       if (err < 0)
+               return err;
+
+       snprintf(rmidi->name, sizeof(rmidi->name),
+                "%s MIDI", tscm->card->shortname);
+       rmidi->private_data = tscm;
+
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                           &midi_capture_ops);
+       stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+
+       /* Set port names for MIDI input. */
+       list_for_each_entry(subs, &stream->substreams, list) {
+               /* TODO: support virtual MIDI ports. */
+               if (subs->number < tscm->spec->midi_capture_ports) {
+                       /* Hardware MIDI ports. */
+                       snprintf(subs->name, sizeof(subs->name),
+                                "%s MIDI %d",
+                                tscm->card->shortname, subs->number + 1);
+               }
+       }
+
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &midi_playback_ops);
+       stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+
+       /* Set port names for MIDI ourput. */
+       list_for_each_entry(subs, &stream->substreams, list) {
+               if (subs->number < tscm->spec->midi_playback_ports) {
+                       /* Hardware MIDI ports only. */
+                       snprintf(subs->name, sizeof(subs->name),
+                                "%s MIDI %d",
+                                tscm->card->shortname, subs->number + 1);
+               }
+       }
+
+       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+       return 0;
+}
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
new file mode 100644 (file)
index 0000000..380d3db
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * tascam-pcm.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "tascam.h"
+
+static void set_buffer_params(struct snd_pcm_hardware *hw)
+{
+       hw->period_bytes_min = 4 * hw->channels_min;
+       hw->period_bytes_max = hw->period_bytes_min * 2048;
+       hw->buffer_bytes_max = hw->period_bytes_max * 2;
+
+       hw->periods_min = 2;
+       hw->periods_max = UINT_MAX;
+}
+
+static int pcm_init_hw_params(struct snd_tscm *tscm,
+                             struct snd_pcm_substream *substream)
+{
+       static const struct snd_pcm_hardware hardware = {
+               .info = SNDRV_PCM_INFO_BATCH |
+                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                       SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_JOINT_DUPLEX |
+                       SNDRV_PCM_INFO_MMAP |
+                       SNDRV_PCM_INFO_MMAP_VALID,
+               .rates = SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 |
+                        SNDRV_PCM_RATE_96000,
+               .rate_min = 44100,
+               .rate_max = 96000,
+               .channels_min = 10,
+               .channels_max = 18,
+       };
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct amdtp_stream *stream;
+       unsigned int pcm_channels;
+
+       runtime->hw = hardware;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
+               stream = &tscm->tx_stream;
+               pcm_channels = tscm->spec->pcm_capture_analog_channels;
+       } else {
+               runtime->hw.formats =
+                               SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32;
+               stream = &tscm->rx_stream;
+               pcm_channels = tscm->spec->pcm_playback_analog_channels;
+       }
+
+       if (tscm->spec->has_adat)
+               pcm_channels += 8;
+       if (tscm->spec->has_spdif)
+               pcm_channels += 2;
+       runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
+
+       set_buffer_params(&runtime->hw);
+
+       return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+       enum snd_tscm_clock clock;
+       unsigned int rate;
+       int err;
+
+       err = snd_tscm_stream_lock_try(tscm);
+       if (err < 0)
+               goto end;
+
+       err = pcm_init_hw_params(tscm, substream);
+       if (err < 0)
+               goto err_locked;
+
+       err = snd_tscm_stream_get_clock(tscm, &clock);
+       if (clock != SND_TSCM_CLOCK_INTERNAL ||
+           amdtp_stream_pcm_running(&tscm->rx_stream) ||
+           amdtp_stream_pcm_running(&tscm->tx_stream)) {
+               err = snd_tscm_stream_get_rate(tscm, &rate);
+               if (err < 0)
+                       goto err_locked;
+               substream->runtime->hw.rate_min = rate;
+               substream->runtime->hw.rate_max = rate;
+       }
+
+       snd_pcm_set_sync(substream);
+end:
+       return err;
+err_locked:
+       snd_tscm_stream_lock_release(tscm);
+       return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+
+       snd_tscm_stream_lock_release(tscm);
+
+       return 0;
+}
+
+static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_tscm *tscm = substream->private_data;
+       int err;
+
+       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               mutex_lock(&tscm->mutex);
+               tscm->substreams_counter++;
+               mutex_unlock(&tscm->mutex);
+       }
+
+       amdtp_tscm_set_pcm_format(&tscm->tx_stream, params_format(hw_params));
+
+       return 0;
+}
+
+static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_tscm *tscm = substream->private_data;
+       int err;
+
+       err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+                                              params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+               mutex_lock(&tscm->mutex);
+               tscm->substreams_counter++;
+               mutex_unlock(&tscm->mutex);
+       }
+
+       amdtp_tscm_set_pcm_format(&tscm->rx_stream, params_format(hw_params));
+
+       return 0;
+}
+
+static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+
+       mutex_lock(&tscm->mutex);
+
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+               tscm->substreams_counter--;
+
+       snd_tscm_stream_stop_duplex(tscm);
+
+       mutex_unlock(&tscm->mutex);
+
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+
+       mutex_lock(&tscm->mutex);
+
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+               tscm->substreams_counter--;
+
+       snd_tscm_stream_stop_duplex(tscm);
+
+       mutex_unlock(&tscm->mutex);
+
+       return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       mutex_lock(&tscm->mutex);
+
+       err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
+       if (err >= 0)
+               amdtp_stream_pcm_prepare(&tscm->tx_stream);
+
+       mutex_unlock(&tscm->mutex);
+
+       return err;
+}
+
+static int pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_tscm *tscm = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       mutex_lock(&tscm->mutex);
+
+       err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
+       if (err >= 0)
+               amdtp_stream_pcm_prepare(&tscm->rx_stream);
+
+       mutex_unlock(&tscm->mutex);
+
+       return err;
+}
+
+static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_tscm *tscm = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_tscm *tscm = substream->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
+{
+       struct snd_tscm *tscm = sbstrm->private_data;
+
+       return amdtp_stream_pcm_pointer(&tscm->tx_stream);
+}
+
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
+{
+       struct snd_tscm *tscm = sbstrm->private_data;
+
+       return amdtp_stream_pcm_pointer(&tscm->rx_stream);
+}
+
+static struct snd_pcm_ops pcm_capture_ops = {
+       .open           = pcm_open,
+       .close          = pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pcm_capture_hw_params,
+       .hw_free        = pcm_capture_hw_free,
+       .prepare        = pcm_capture_prepare,
+       .trigger        = pcm_capture_trigger,
+       .pointer        = pcm_capture_pointer,
+       .page           = snd_pcm_lib_get_vmalloc_page,
+};
+
+static struct snd_pcm_ops pcm_playback_ops = {
+       .open           = pcm_open,
+       .close          = pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = pcm_playback_hw_params,
+       .hw_free        = pcm_playback_hw_free,
+       .prepare        = pcm_playback_prepare,
+       .trigger        = pcm_playback_trigger,
+       .pointer        = pcm_playback_pointer,
+       .page           = snd_pcm_lib_get_vmalloc_page,
+       .mmap           = snd_pcm_lib_mmap_vmalloc,
+};
+
+int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = tscm;
+       snprintf(pcm->name, sizeof(pcm->name),
+                "%s PCM", tscm->card->shortname);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+
+       return 0;
+}
diff --git a/sound/firewire/tascam/tascam-proc.c b/sound/firewire/tascam/tascam-proc.c
new file mode 100644 (file)
index 0000000..bfd4a4c
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * tascam-proc.h - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./tascam.h"
+
+static void proc_read_firmware(struct snd_info_entry *entry,
+                              struct snd_info_buffer *buffer)
+{
+       struct snd_tscm *tscm = entry->private_data;
+       __be32 data;
+       unsigned int reg, fpga, arm, hw;
+       int err;
+
+       err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
+                       TSCM_ADDR_BASE + TSCM_OFFSET_FIRMWARE_REGISTER,
+                       &data, sizeof(data), 0);
+       if (err < 0)
+               return;
+       reg = be32_to_cpu(data);
+
+       err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
+                       TSCM_ADDR_BASE + TSCM_OFFSET_FIRMWARE_FPGA,
+                       &data, sizeof(data), 0);
+       if (err < 0)
+               return;
+       fpga = be32_to_cpu(data);
+
+       err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
+                       TSCM_ADDR_BASE + TSCM_OFFSET_FIRMWARE_ARM,
+                       &data, sizeof(data), 0);
+       if (err < 0)
+               return;
+       arm = be32_to_cpu(data);
+
+       err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
+                       TSCM_ADDR_BASE + TSCM_OFFSET_FIRMWARE_HW,
+                       &data, sizeof(data), 0);
+       if (err < 0)
+               return;
+       hw = be32_to_cpu(data);
+
+       snd_iprintf(buffer, "Register: %d (0x%08x)\n", reg & 0xffff, reg);
+       snd_iprintf(buffer, "FPGA:     %d (0x%08x)\n", fpga & 0xffff, fpga);
+       snd_iprintf(buffer, "ARM:      %d (0x%08x)\n", arm & 0xffff, arm);
+       snd_iprintf(buffer, "Hardware: %d (0x%08x)\n", hw >> 16, hw);
+}
+
+static void add_node(struct snd_tscm *tscm, struct snd_info_entry *root,
+                    const char *name,
+                    void (*op)(struct snd_info_entry *e,
+                               struct snd_info_buffer *b))
+{
+       struct snd_info_entry *entry;
+
+       entry = snd_info_create_card_entry(tscm->card, name, root);
+       if (entry == NULL)
+               return;
+
+       snd_info_set_text_ops(entry, tscm, op);
+       if (snd_info_register(entry) < 0)
+               snd_info_free_entry(entry);
+}
+
+void snd_tscm_proc_init(struct snd_tscm *tscm)
+{
+       struct snd_info_entry *root;
+
+       /*
+        * All nodes are automatically removed at snd_card_disconnect(),
+        * by following to link list.
+        */
+       root = snd_info_create_card_entry(tscm->card, "firewire",
+                                         tscm->card->proc_root);
+       if (root == NULL)
+               return;
+       root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       if (snd_info_register(root) < 0) {
+               snd_info_free_entry(root);
+               return;
+       }
+
+       add_node(tscm, root, "firmware", proc_read_firmware);
+}
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
new file mode 100644 (file)
index 0000000..0e6dd5c
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * tascam-stream.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/delay.h>
+#include "tascam.h"
+
+#define CALLBACK_TIMEOUT 500
+
+static int get_clock(struct snd_tscm *tscm, u32 *data)
+{
+       __be32 reg;
+       int err;
+
+       err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
+                                &reg, sizeof(reg), 0);
+       if (err >= 0)
+               *data = be32_to_cpu(reg);
+
+       return err;
+}
+
+static int set_clock(struct snd_tscm *tscm, unsigned int rate,
+                    enum snd_tscm_clock clock)
+{
+       u32 data;
+       __be32 reg;
+       int err;
+
+       err = get_clock(tscm, &data);
+       if (err < 0)
+               return err;
+       data &= 0x0000ffff;
+
+       if (rate > 0) {
+               data &= 0x000000ff;
+               /* Base rate. */
+               if ((rate % 44100) == 0) {
+                       data |= 0x00000100;
+                       /* Multiplier. */
+                       if (rate / 44100 == 2)
+                               data |= 0x00008000;
+               } else if ((rate % 48000) == 0) {
+                       data |= 0x00000200;
+                       /* Multiplier. */
+                       if (rate / 48000 == 2)
+                               data |= 0x00008000;
+               } else {
+                       return -EAGAIN;
+               }
+       }
+
+       if (clock != INT_MAX) {
+               data &= 0x0000ff00;
+               data |= clock + 1;
+       }
+
+       reg = cpu_to_be32(data);
+
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       if (data & 0x00008000)
+               reg = cpu_to_be32(0x0000001a);
+       else
+               reg = cpu_to_be32(0x0000000d);
+
+       return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 TSCM_ADDR_BASE + TSCM_OFFSET_MULTIPLEX_MODE,
+                                 &reg, sizeof(reg), 0);
+}
+
+int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate)
+{
+       u32 data = 0x0;
+       unsigned int trials = 0;
+       int err;
+
+       while (data == 0x0 || trials++ < 5) {
+               err = get_clock(tscm, &data);
+               if (err < 0)
+                       return err;
+
+               data = (data & 0xff000000) >> 24;
+       }
+
+       /* Check base rate. */
+       if ((data & 0x0f) == 0x01)
+               *rate = 44100;
+       else if ((data & 0x0f) == 0x02)
+               *rate = 48000;
+       else
+               return -EAGAIN;
+
+       /* Check multiplier. */
+       if ((data & 0xf0) == 0x80)
+               *rate *= 2;
+       else if ((data & 0xf0) != 0x00)
+               return -EAGAIN;
+
+       return err;
+}
+
+int snd_tscm_stream_get_clock(struct snd_tscm *tscm, enum snd_tscm_clock *clock)
+{
+       u32 data;
+       int err;
+
+       err = get_clock(tscm, &data);
+       if (err < 0)
+               return err;
+
+       *clock = ((data & 0x00ff0000) >> 16) - 1;
+       if (*clock < 0 || *clock > SND_TSCM_CLOCK_ADAT)
+               return -EIO;
+
+       return 0;
+}
+
+static int enable_data_channels(struct snd_tscm *tscm)
+{
+       __be32 reg;
+       u32 data;
+       unsigned int i;
+       int err;
+
+       data = 0;
+       for (i = 0; i < tscm->spec->pcm_capture_analog_channels; ++i)
+               data |= BIT(i);
+       if (tscm->spec->has_adat)
+               data |= 0x0000ff00;
+       if (tscm->spec->has_spdif)
+               data |= 0x00030000;
+
+       reg = cpu_to_be32(data);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_TX_PCM_CHANNELS,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       data = 0;
+       for (i = 0; i < tscm->spec->pcm_playback_analog_channels; ++i)
+               data |= BIT(i);
+       if (tscm->spec->has_adat)
+               data |= 0x0000ff00;
+       if (tscm->spec->has_spdif)
+               data |= 0x00030000;
+
+       reg = cpu_to_be32(data);
+       return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 TSCM_ADDR_BASE + TSCM_OFFSET_RX_PCM_CHANNELS,
+                                 &reg, sizeof(reg), 0);
+}
+
+static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
+{
+       __be32 reg;
+       int err;
+
+       /* Set an option for unknown purpose. */
+       reg = cpu_to_be32(0x00200000);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       err = enable_data_channels(tscm);
+       if (err < 0)
+               return err;
+
+       return set_clock(tscm, rate, INT_MAX);
+}
+
+static void finish_session(struct snd_tscm *tscm)
+{
+       __be32 reg;
+
+       reg = 0;
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
+                          &reg, sizeof(reg), 0);
+
+       reg = 0;
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
+                          &reg, sizeof(reg), 0);
+
+}
+
+static int begin_session(struct snd_tscm *tscm)
+{
+       __be32 reg;
+       int err;
+
+       reg = cpu_to_be32(0x00000001);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       reg = cpu_to_be32(0x00000001);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       /* Set an option for unknown purpose. */
+       reg = cpu_to_be32(0x00002000);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       /* Start multiplexing PCM samples on packets. */
+       reg = cpu_to_be32(0x00000001);
+       return snd_fw_transaction(tscm->unit,
+                                 TCODE_WRITE_QUADLET_REQUEST,
+                                 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_ON,
+                                 &reg, sizeof(reg), 0);
+}
+
+static void release_resources(struct snd_tscm *tscm)
+{
+       __be32 reg;
+
+       /* Unregister channels. */
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+                          &reg, sizeof(reg), 0);
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+                          &reg, sizeof(reg), 0);
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+                          &reg, sizeof(reg), 0);
+
+       /* Release isochronous resources. */
+       fw_iso_resources_free(&tscm->tx_resources);
+       fw_iso_resources_free(&tscm->rx_resources);
+}
+
+static int keep_resources(struct snd_tscm *tscm, unsigned int rate)
+{
+       __be32 reg;
+       int err;
+
+       /* Keep resources for in-stream. */
+       err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate);
+       if (err < 0)
+               return err;
+       err = fw_iso_resources_allocate(&tscm->tx_resources,
+                       amdtp_stream_get_max_payload(&tscm->tx_stream),
+                       fw_parent_device(tscm->unit)->max_speed);
+       if (err < 0)
+               goto error;
+
+       /* Keep resources for out-stream. */
+       err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate);
+       if (err < 0)
+               return err;
+       err = fw_iso_resources_allocate(&tscm->rx_resources,
+                       amdtp_stream_get_max_payload(&tscm->rx_stream),
+                       fw_parent_device(tscm->unit)->max_speed);
+       if (err < 0)
+               return err;
+
+       /* Register the isochronous channel for transmitting stream. */
+       reg = cpu_to_be32(tscm->tx_resources.channel);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               goto error;
+
+       /* Unknown */
+       reg = cpu_to_be32(0x00000002);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               goto error;
+
+       /* Register the isochronous channel for receiving stream. */
+       reg = cpu_to_be32(tscm->rx_resources.channel);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               goto error;
+
+       return 0;
+error:
+       release_resources(tscm);
+       return err;
+}
+
+int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
+{
+       unsigned int pcm_channels;
+       int err;
+
+       /* For out-stream. */
+       err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit);
+       if (err < 0)
+               return err;
+       pcm_channels = tscm->spec->pcm_playback_analog_channels;
+       if (tscm->spec->has_adat)
+               pcm_channels += 8;
+       if (tscm->spec->has_spdif)
+               pcm_channels += 2;
+       err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM,
+                             pcm_channels);
+       if (err < 0)
+               return err;
+
+       /* For in-stream. */
+       err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit);
+       if (err < 0)
+               return err;
+       pcm_channels = tscm->spec->pcm_capture_analog_channels;
+       if (tscm->spec->has_adat)
+               pcm_channels += 8;
+       if (tscm->spec->has_spdif)
+               pcm_channels += 2;
+       err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM,
+                             pcm_channels);
+       if (err < 0)
+               amdtp_stream_destroy(&tscm->rx_stream);
+
+       return 0;
+}
+
+/* At bus reset, streaming is stopped and some registers are clear. */
+void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
+{
+       amdtp_stream_pcm_abort(&tscm->tx_stream);
+       amdtp_stream_stop(&tscm->tx_stream);
+
+       amdtp_stream_pcm_abort(&tscm->rx_stream);
+       amdtp_stream_stop(&tscm->rx_stream);
+}
+
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
+void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
+{
+       amdtp_stream_destroy(&tscm->rx_stream);
+       amdtp_stream_destroy(&tscm->tx_stream);
+
+       fw_iso_resources_destroy(&tscm->rx_resources);
+       fw_iso_resources_destroy(&tscm->tx_resources);
+}
+
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+{
+       unsigned int curr_rate;
+       int err;
+
+       if (tscm->substreams_counter == 0)
+               return 0;
+
+       err = snd_tscm_stream_get_rate(tscm, &curr_rate);
+       if (err < 0)
+               return err;
+       if (curr_rate != rate ||
+           amdtp_streaming_error(&tscm->tx_stream) ||
+           amdtp_streaming_error(&tscm->rx_stream)) {
+               finish_session(tscm);
+
+               amdtp_stream_stop(&tscm->tx_stream);
+               amdtp_stream_stop(&tscm->rx_stream);
+
+               release_resources(tscm);
+       }
+
+       if (!amdtp_stream_running(&tscm->tx_stream)) {
+               amdtp_stream_set_sync(CIP_SYNC_TO_DEVICE,
+                                     &tscm->tx_stream, &tscm->rx_stream);
+               err = keep_resources(tscm, rate);
+               if (err < 0)
+                       goto error;
+
+               err = set_stream_formats(tscm, rate);
+               if (err < 0)
+                       goto error;
+
+               err = begin_session(tscm);
+               if (err < 0)
+                       goto error;
+
+               err = amdtp_stream_start(&tscm->tx_stream,
+                               tscm->tx_resources.channel,
+                               fw_parent_device(tscm->unit)->max_speed);
+               if (err < 0)
+                       goto error;
+
+               if (!amdtp_stream_wait_callback(&tscm->tx_stream,
+                                               CALLBACK_TIMEOUT)) {
+                       err = -ETIMEDOUT;
+                       goto error;
+               }
+       }
+
+       if (!amdtp_stream_running(&tscm->rx_stream)) {
+               err = amdtp_stream_start(&tscm->rx_stream,
+                               tscm->rx_resources.channel,
+                               fw_parent_device(tscm->unit)->max_speed);
+               if (err < 0)
+                       goto error;
+
+               if (!amdtp_stream_wait_callback(&tscm->rx_stream,
+                                               CALLBACK_TIMEOUT)) {
+                       err = -ETIMEDOUT;
+                       goto error;
+               }
+       }
+
+       return 0;
+error:
+       amdtp_stream_stop(&tscm->tx_stream);
+       amdtp_stream_stop(&tscm->rx_stream);
+
+       finish_session(tscm);
+       release_resources(tscm);
+
+       return err;
+}
+
+void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
+{
+       if (tscm->substreams_counter > 0)
+               return;
+
+       amdtp_stream_stop(&tscm->tx_stream);
+       amdtp_stream_stop(&tscm->rx_stream);
+
+       finish_session(tscm);
+       release_resources(tscm);
+}
+
+void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
+{
+       tscm->dev_lock_changed = true;
+       wake_up(&tscm->hwdep_wait);
+}
+
+int snd_tscm_stream_lock_try(struct snd_tscm *tscm)
+{
+       int err;
+
+       spin_lock_irq(&tscm->lock);
+
+       /* user land lock this */
+       if (tscm->dev_lock_count < 0) {
+               err = -EBUSY;
+               goto end;
+       }
+
+       /* this is the first time */
+       if (tscm->dev_lock_count++ == 0)
+               snd_tscm_stream_lock_changed(tscm);
+       err = 0;
+end:
+       spin_unlock_irq(&tscm->lock);
+       return err;
+}
+
+void snd_tscm_stream_lock_release(struct snd_tscm *tscm)
+{
+       spin_lock_irq(&tscm->lock);
+
+       if (WARN_ON(tscm->dev_lock_count <= 0))
+               goto end;
+       if (--tscm->dev_lock_count == 0)
+               snd_tscm_stream_lock_changed(tscm);
+end:
+       spin_unlock_irq(&tscm->lock);
+}
diff --git a/sound/firewire/tascam/tascam-transaction.c b/sound/firewire/tascam/tascam-transaction.c
new file mode 100644 (file)
index 0000000..904ce03
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * tascam-transaction.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "tascam.h"
+
+/*
+ * When return minus value, given argument is not MIDI status.
+ * When return 0, given argument is a beginning of system exclusive.
+ * When return the others, given argument is MIDI data.
+ */
+static inline int calculate_message_bytes(u8 status)
+{
+       switch (status) {
+       case 0xf6:      /* Tune request. */
+       case 0xf8:      /* Timing clock. */
+       case 0xfa:      /* Start. */
+       case 0xfb:      /* Continue. */
+       case 0xfc:      /* Stop. */
+       case 0xfe:      /* Active sensing. */
+       case 0xff:      /* System reset. */
+               return 1;
+       case 0xf1:      /* MIDI time code quarter frame. */
+       case 0xf3:      /* Song select. */
+               return 2;
+       case 0xf2:      /* Song position pointer. */
+               return 3;
+       case 0xf0:      /* Exclusive. */
+               return 0;
+       case 0xf7:      /* End of exclusive. */
+               break;
+       case 0xf4:      /* Undefined. */
+       case 0xf5:      /* Undefined. */
+       case 0xf9:      /* Undefined. */
+       case 0xfd:      /* Undefined. */
+               break;
+       default:
+               switch (status & 0xf0) {
+               case 0x80:      /* Note on. */
+               case 0x90:      /* Note off. */
+               case 0xa0:      /* Polyphonic key pressure. */
+               case 0xb0:      /* Control change and Mode change. */
+               case 0xe0:      /* Pitch bend change. */
+                       return 3;
+               case 0xc0:      /* Program change. */
+               case 0xd0:      /* Channel pressure. */
+                       return 2;
+               default:
+               break;
+               }
+       break;
+       }
+
+       return -EINVAL;
+}
+
+static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf)
+{
+       struct snd_tscm *tscm = substream->rmidi->private_data;
+       unsigned int port = substream->number;
+       int i, len, consume;
+       u8 *label, *msg;
+       u8 status;
+
+       /* The first byte is used for label, the rest for MIDI bytes. */
+       label = buf;
+       msg = buf + 1;
+
+       consume = snd_rawmidi_transmit_peek(substream, msg, 3);
+       if (consume == 0)
+               return 0;
+
+       /* On exclusive message. */
+       if (tscm->on_sysex[port]) {
+               /* Seek the end of exclusives. */
+               for (i = 0; i < consume; ++i) {
+                       if (msg[i] == 0xf7) {
+                               tscm->on_sysex[port] = false;
+                               break;
+                       }
+               }
+
+               /* At the end of exclusive message, use label 0x07. */
+               if (!tscm->on_sysex[port]) {
+                       consume = i + 1;
+                       *label = (port << 4) | 0x07;
+               /* During exclusive message, use label 0x04. */
+               } else if (consume == 3) {
+                       *label = (port << 4) | 0x04;
+               /* We need to fill whole 3 bytes. Go to next change. */
+               } else {
+                       return 0;
+               }
+
+               len = consume;
+       } else {
+               /* The beginning of exclusives. */
+               if (msg[0] == 0xf0) {
+                       /* Transfer it in next chance in another condition. */
+                       tscm->on_sysex[port] = true;
+                       return 0;
+               } else {
+                       /* On running-status. */
+                       if ((msg[0] & 0x80) != 0x80)
+                               status = tscm->running_status[port];
+                       else
+                               status = msg[0];
+
+                       /* Calculate consume bytes. */
+                       len = calculate_message_bytes(status);
+                       if (len <= 0)
+                               return 0;
+
+                       /* On running-status. */
+                       if ((msg[0] & 0x80) != 0x80) {
+                               /* Enough MIDI bytes were not retrieved. */
+                               if (consume < len - 1)
+                                       return 0;
+                               consume = len - 1;
+
+                               msg[2] = msg[1];
+                               msg[1] = msg[0];
+                               msg[0] = tscm->running_status[port];
+                       } else {
+                               /* Enough MIDI bytes were not retrieved. */
+                               if (consume < len)
+                                       return 0;
+                               consume = len;
+
+                               tscm->running_status[port] = msg[0];
+                       }
+               }
+
+               *label = (port << 4) | (msg[0] >> 4);
+       }
+
+       if (len > 0 && len < 3)
+               memset(msg + len, 0, 3 - len);
+
+       return consume;
+}
+
+static void handle_midi_tx(struct fw_card *card, struct fw_request *request,
+                          int tcode, int destination, int source,
+                          int generation, unsigned long long offset,
+                          void *data, size_t length, void *callback_data)
+{
+       struct snd_tscm *tscm = callback_data;
+       u32 *buf = (u32 *)data;
+       unsigned int messages;
+       unsigned int i;
+       unsigned int port;
+       struct snd_rawmidi_substream *substream;
+       u8 *b;
+       int bytes;
+
+       if (offset != tscm->async_handler.offset)
+               goto end;
+
+       messages = length / 8;
+       for (i = 0; i < messages; i++) {
+               b = (u8 *)(buf + i * 2);
+
+               port = b[0] >> 4;
+               /* TODO: support virtual MIDI ports. */
+               if (port >= tscm->spec->midi_capture_ports)
+                       goto end;
+
+               /* Assume the message length. */
+               bytes = calculate_message_bytes(b[1]);
+               /* On MIDI data or exclusives. */
+               if (bytes <= 0) {
+                       /* Seek the end of exclusives. */
+                       for (bytes = 1; bytes < 4; bytes++) {
+                               if (b[bytes] == 0xf7)
+                                       break;
+                       }
+                       if (bytes == 4)
+                               bytes = 3;
+               }
+
+               substream = ACCESS_ONCE(tscm->tx_midi_substreams[port]);
+               if (substream != NULL)
+                       snd_rawmidi_receive(substream, b + 1, bytes);
+       }
+end:
+       fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+int snd_tscm_transaction_register(struct snd_tscm *tscm)
+{
+       static const struct fw_address_region resp_register_region = {
+               .start  = 0xffffe0000000ull,
+               .end    = 0xffffe000ffffull,
+       };
+       unsigned int i;
+       int err;
+
+       /*
+        * Usually, two quadlets are transferred by one transaction. The first
+        * quadlet has MIDI messages, the rest includes timestamp.
+        * Sometimes, 8 set of the data is transferred by a block transaction.
+        */
+       tscm->async_handler.length = 8 * 8;
+       tscm->async_handler.address_callback = handle_midi_tx;
+       tscm->async_handler.callback_data = tscm;
+
+       err = fw_core_add_address_handler(&tscm->async_handler,
+                                         &resp_register_region);
+       if (err < 0)
+               return err;
+
+       err = snd_tscm_transaction_reregister(tscm);
+       if (err < 0)
+               goto error;
+
+       for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) {
+               err = snd_fw_async_midi_port_init(
+                               &tscm->out_ports[i], tscm->unit,
+                               TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD,
+                               4, fill_message);
+               if (err < 0)
+                       goto error;
+       }
+
+       return err;
+error:
+       fw_core_remove_address_handler(&tscm->async_handler);
+       return err;
+}
+
+/* At bus reset, these registers are cleared. */
+int snd_tscm_transaction_reregister(struct snd_tscm *tscm)
+{
+       struct fw_device *device = fw_parent_device(tscm->unit);
+       __be32 reg;
+       int err;
+
+       /* Register messaging address. Block transaction is not allowed. */
+       reg = cpu_to_be32((device->card->node_id << 16) |
+                         (tscm->async_handler.offset >> 32));
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       reg = cpu_to_be32(tscm->async_handler.offset);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
+                                &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       /* Turn on messaging. */
+       reg = cpu_to_be32(0x00000001);
+       err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
+                                 &reg, sizeof(reg), 0);
+       if (err < 0)
+               return err;
+
+       /* Turn on FireWire LED. */
+       reg = cpu_to_be32(0x0001008e);
+       return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                                 TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
+                                 &reg, sizeof(reg), 0);
+}
+
+void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
+{
+       __be32 reg;
+       unsigned int i;
+
+       /* Turn off FireWire LED. */
+       reg = cpu_to_be32(0x0000008e);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
+                          &reg, sizeof(reg), 0);
+
+       /* Turn off messaging. */
+       reg = cpu_to_be32(0x00000000);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
+                          &reg, sizeof(reg), 0);
+
+       /* Unregister the address. */
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
+                          &reg, sizeof(reg), 0);
+       snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
+                          TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
+                          &reg, sizeof(reg), 0);
+
+       fw_core_remove_address_handler(&tscm->async_handler);
+       for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++)
+               snd_fw_async_midi_port_destroy(&tscm->out_ports[i]);
+}
diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c
new file mode 100644 (file)
index 0000000..ee0bc18
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * tascam.c - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "tascam.h"
+
+MODULE_DESCRIPTION("TASCAM FireWire series Driver");
+MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
+MODULE_LICENSE("GPL v2");
+
+static struct snd_tscm_spec model_specs[] = {
+       {
+               .name = "FW-1884",
+               .has_adat = true,
+               .has_spdif = true,
+               .pcm_capture_analog_channels = 8,
+               .pcm_playback_analog_channels = 8,
+               .midi_capture_ports = 4,
+               .midi_playback_ports = 4,
+               .is_controller = true,
+       },
+       {
+               .name = "FW-1082",
+               .has_adat = false,
+               .has_spdif = true,
+               .pcm_capture_analog_channels = 8,
+               .pcm_playback_analog_channels = 2,
+               .midi_capture_ports = 2,
+               .midi_playback_ports = 2,
+               .is_controller = true,
+       },
+       /* FW-1804 may be supported. */
+};
+
+static int identify_model(struct snd_tscm *tscm)
+{
+       struct fw_device *fw_dev = fw_parent_device(tscm->unit);
+       const u32 *config_rom = fw_dev->config_rom;
+       char model[9];
+       unsigned int i;
+       u8 c;
+
+       if (fw_dev->config_rom_length < 30) {
+               dev_err(&tscm->unit->device,
+                       "Configuration ROM is too short.\n");
+               return -ENODEV;
+       }
+
+       /* Pick up model name from certain addresses. */
+       for (i = 0; i < 8; i++) {
+               c = config_rom[28 + i / 4] >> (24 - 8 * (i % 4));
+               if (c == '\0')
+                       break;
+               model[i] = c;
+       }
+       model[i] = '\0';
+
+       for (i = 0; i < ARRAY_SIZE(model_specs); i++) {
+               if (strcmp(model, model_specs[i].name) == 0) {
+                       tscm->spec = &model_specs[i];
+                       break;
+               }
+       }
+       if (tscm->spec == NULL)
+               return -ENODEV;
+
+       strcpy(tscm->card->driver, "FW-TASCAM");
+       strcpy(tscm->card->shortname, model);
+       strcpy(tscm->card->mixername, model);
+       snprintf(tscm->card->longname, sizeof(tscm->card->longname),
+                "TASCAM %s, GUID %08x%08x at %s, S%d", model,
+                fw_dev->config_rom[3], fw_dev->config_rom[4],
+                dev_name(&tscm->unit->device), 100 << fw_dev->max_speed);
+
+       return 0;
+}
+
+static void tscm_card_free(struct snd_card *card)
+{
+       struct snd_tscm *tscm = card->private_data;
+
+       snd_tscm_transaction_unregister(tscm);
+       snd_tscm_stream_destroy_duplex(tscm);
+
+       fw_unit_put(tscm->unit);
+
+       mutex_destroy(&tscm->mutex);
+}
+
+static int snd_tscm_probe(struct fw_unit *unit,
+                          const struct ieee1394_device_id *entry)
+{
+       struct snd_card *card;
+       struct snd_tscm *tscm;
+       int err;
+
+       /* create card */
+       err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+                          sizeof(struct snd_tscm), &card);
+       if (err < 0)
+               return err;
+       card->private_free = tscm_card_free;
+
+       /* initialize myself */
+       tscm = card->private_data;
+       tscm->card = card;
+       tscm->unit = fw_unit_get(unit);
+
+       mutex_init(&tscm->mutex);
+       spin_lock_init(&tscm->lock);
+       init_waitqueue_head(&tscm->hwdep_wait);
+
+       err = identify_model(tscm);
+       if (err < 0)
+               goto error;
+
+       snd_tscm_proc_init(tscm);
+
+       err = snd_tscm_stream_init_duplex(tscm);
+       if (err < 0)
+               goto error;
+
+       err = snd_tscm_create_pcm_devices(tscm);
+       if (err < 0)
+               goto error;
+
+       err = snd_tscm_transaction_register(tscm);
+       if (err < 0)
+               goto error;
+
+       err = snd_tscm_create_midi_devices(tscm);
+       if (err < 0)
+               goto error;
+
+       err = snd_tscm_create_hwdep_device(tscm);
+       if (err < 0)
+               goto error;
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dev_set_drvdata(&unit->device, tscm);
+
+       return err;
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static void snd_tscm_update(struct fw_unit *unit)
+{
+       struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
+
+       snd_tscm_transaction_reregister(tscm);
+
+       mutex_lock(&tscm->mutex);
+       snd_tscm_stream_update_duplex(tscm);
+       mutex_unlock(&tscm->mutex);
+}
+
+static void snd_tscm_remove(struct fw_unit *unit)
+{
+       struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
+
+       /* No need to wait for releasing card object in this context. */
+       snd_card_free_when_closed(tscm->card);
+}
+
+static const struct ieee1394_device_id snd_tscm_id_table[] = {
+       {
+               .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_SPECIFIER_ID,
+               .vendor_id = 0x00022e,
+               .specifier_id = 0x00022e,
+       },
+       /* FE-08 requires reverse-engineering because it just has faders. */
+       {}
+};
+MODULE_DEVICE_TABLE(ieee1394, snd_tscm_id_table);
+
+static struct fw_driver tscm_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "snd-firewire-tascam",
+               .bus = &fw_bus_type,
+       },
+       .probe    = snd_tscm_probe,
+       .update   = snd_tscm_update,
+       .remove   = snd_tscm_remove,
+       .id_table = snd_tscm_id_table,
+};
+
+static int __init snd_tscm_init(void)
+{
+       return driver_register(&tscm_driver.driver);
+}
+
+static void __exit snd_tscm_exit(void)
+{
+       driver_unregister(&tscm_driver.driver);
+}
+
+module_init(snd_tscm_init);
+module_exit(snd_tscm_exit);
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
new file mode 100644 (file)
index 0000000..2d028d2
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * tascam.h - a part of driver for TASCAM FireWire series
+ *
+ * Copyright (c) 2015 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef SOUND_TASCAM_H_INCLUDED
+#define SOUND_TASCAM_H_INCLUDED
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+#include <sound/rawmidi.h>
+
+#include "../lib.h"
+#include "../amdtp-stream.h"
+#include "../iso-resources.h"
+
+struct snd_tscm_spec {
+       const char *const name;
+       bool has_adat;
+       bool has_spdif;
+       unsigned int pcm_capture_analog_channels;
+       unsigned int pcm_playback_analog_channels;
+       unsigned int midi_capture_ports;
+       unsigned int midi_playback_ports;
+       bool is_controller;
+};
+
+#define TSCM_MIDI_IN_PORT_MAX  4
+#define TSCM_MIDI_OUT_PORT_MAX 4
+
+struct snd_tscm {
+       struct snd_card *card;
+       struct fw_unit *unit;
+
+       struct mutex mutex;
+       spinlock_t lock;
+
+       const struct snd_tscm_spec *spec;
+
+       struct fw_iso_resources tx_resources;
+       struct fw_iso_resources rx_resources;
+       struct amdtp_stream tx_stream;
+       struct amdtp_stream rx_stream;
+       unsigned int substreams_counter;
+
+       int dev_lock_count;
+       bool dev_lock_changed;
+       wait_queue_head_t hwdep_wait;
+
+       /* For MIDI message incoming transactions. */
+       struct fw_address_handler async_handler;
+       struct snd_rawmidi_substream *tx_midi_substreams[TSCM_MIDI_IN_PORT_MAX];
+
+       /* For MIDI message outgoing transactions. */
+       struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
+       u8 running_status[TSCM_MIDI_OUT_PORT_MAX];
+       bool on_sysex[TSCM_MIDI_OUT_PORT_MAX];
+
+       /* For control messages. */
+       struct snd_firewire_tascam_status *status;
+};
+
+#define TSCM_ADDR_BASE                 0xffff00000000ull
+
+#define TSCM_OFFSET_FIRMWARE_REGISTER  0x0000
+#define TSCM_OFFSET_FIRMWARE_FPGA      0x0004
+#define TSCM_OFFSET_FIRMWARE_ARM       0x0008
+#define TSCM_OFFSET_FIRMWARE_HW                0x000c
+
+#define TSCM_OFFSET_ISOC_TX_CH         0x0200
+#define TSCM_OFFSET_UNKNOWN            0x0204
+#define TSCM_OFFSET_START_STREAMING    0x0208
+#define TSCM_OFFSET_ISOC_RX_CH         0x020c
+#define TSCM_OFFSET_ISOC_RX_ON         0x0210  /* Little conviction. */
+#define TSCM_OFFSET_TX_PCM_CHANNELS    0x0214
+#define TSCM_OFFSET_RX_PCM_CHANNELS    0x0218
+#define TSCM_OFFSET_MULTIPLEX_MODE     0x021c
+#define TSCM_OFFSET_ISOC_TX_ON         0x0220
+/* Unknown                             0x0224 */
+#define TSCM_OFFSET_CLOCK_STATUS       0x0228
+#define TSCM_OFFSET_SET_OPTION         0x022c
+
+#define TSCM_OFFSET_MIDI_TX_ON         0x0300
+#define TSCM_OFFSET_MIDI_TX_ADDR_HI    0x0304
+#define TSCM_OFFSET_MIDI_TX_ADDR_LO    0x0308
+
+#define TSCM_OFFSET_LED_POWER          0x0404
+
+#define TSCM_OFFSET_MIDI_RX_QUAD       0x4000
+
+enum snd_tscm_clock {
+       SND_TSCM_CLOCK_INTERNAL = 0,
+       SND_TSCM_CLOCK_WORD     = 1,
+       SND_TSCM_CLOCK_SPDIF    = 2,
+       SND_TSCM_CLOCK_ADAT     = 3,
+};
+
+int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
+                 enum amdtp_stream_direction dir, unsigned int pcm_channels);
+int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate);
+int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
+                                     struct snd_pcm_runtime *runtime);
+void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format);
+
+int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate);
+int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
+                             enum snd_tscm_clock *clock);
+int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
+void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
+void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
+void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
+
+void snd_tscm_stream_lock_changed(struct snd_tscm *tscm);
+int snd_tscm_stream_lock_try(struct snd_tscm *tscm);
+void snd_tscm_stream_lock_release(struct snd_tscm *tscm);
+
+int snd_tscm_transaction_register(struct snd_tscm *tscm);
+int snd_tscm_transaction_reregister(struct snd_tscm *tscm);
+void snd_tscm_transaction_unregister(struct snd_tscm *tscm);
+
+void snd_tscm_proc_init(struct snd_tscm *tscm);
+
+int snd_tscm_create_pcm_devices(struct snd_tscm *tscm);
+
+int snd_tscm_create_midi_devices(struct snd_tscm *tscm);
+
+int snd_tscm_create_hwdep_device(struct snd_tscm *tscm);
+
+#endif
index 33ba77dd32f2f174fd4d57dd52ff979ec9b0b510..cb89ec7c8147b2d44a90061ac531514ef5ce4de2 100644 (file)
@@ -227,7 +227,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
 void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
                                 int stream)
 {
-       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
+       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
 
@@ -385,14 +385,13 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
                break;
 
        case HDAC_EXT_STREAM_TYPE_HOST:
-               if (stream->decoupled) {
+               if (stream->decoupled && !stream->link_locked)
                        snd_hdac_ext_stream_decouple(ebus, stream, false);
-                       snd_hdac_stream_release(&stream->hstream);
-               }
+               snd_hdac_stream_release(&stream->hstream);
                break;
 
        case HDAC_EXT_STREAM_TYPE_LINK:
-               if (stream->decoupled)
+               if (stream->decoupled && !stream->hstream.opened)
                        snd_hdac_ext_stream_decouple(ebus, stream, false);
                spin_lock_irq(&bus->reg_lock);
                stream->link_locked = 0;
index 89c2711baaaf40c72753b50e05628e53cd0771ea..3060e2aee36fd736ce3755559d26c7049ba11218 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/export.h>
 #include <sound/hdaudio.h>
 
@@ -63,9 +64,21 @@ static int hda_bus_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
+static int hda_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       char modalias[32];
+
+       snd_hdac_codec_modalias(dev_to_hdac_dev(dev), modalias,
+                               sizeof(modalias));
+       if (add_uevent_var(env, "MODALIAS=%s", modalias))
+               return -ENOMEM;
+       return 0;
+}
+
 struct bus_type snd_hda_bus_type = {
        .name = "hdaudio",
        .match = hda_bus_match,
+       .uevent = hda_uevent,
 };
 EXPORT_SYMBOL_GPL(snd_hda_bus_type);
 
index 27c447e4fe5c6af5017389ca26cb2c57e534973c..0e81ea89a5965a49a80e52c6405d9a456cc9decf 100644 (file)
@@ -172,6 +172,15 @@ static void process_unsol_events(struct work_struct *work)
        }
 }
 
+/**
+ * snd_hdac_bus_add_device - Add a codec to bus
+ * @bus: HDA core bus
+ * @codec: HDA core device to add
+ *
+ * Adds the given codec to the list in the bus.  The caddr_tbl array
+ * and codec_powered bits are updated, as well.
+ * Returns zero if success, or a negative error code.
+ */
 int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec)
 {
        if (bus->caddr_tbl[codec->addr]) {
@@ -188,6 +197,11 @@ int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device);
 
+/**
+ * snd_hdac_bus_remove_device - Remove a codec from bus
+ * @bus: HDA core bus
+ * @codec: HDA core device to remove
+ */
 void snd_hdac_bus_remove_device(struct hdac_bus *bus,
                                struct hdac_device *codec)
 {
index db96042a497f040059585adb9465d2357b28b265..e361024eabb6371bef25a888bcd8ea58a5499913 100644 (file)
@@ -163,6 +163,43 @@ void snd_hdac_device_unregister(struct hdac_device *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_device_unregister);
 
+/**
+ * snd_hdac_device_set_chip_name - set/update the codec name
+ * @codec: the HDAC device
+ * @name: name string to set
+ *
+ * Returns 0 if the name is set or updated, or a negative error code.
+ */
+int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name)
+{
+       char *newname;
+
+       if (!name)
+               return 0;
+       newname = kstrdup(name, GFP_KERNEL);
+       if (!newname)
+               return -ENOMEM;
+       kfree(codec->chip_name);
+       codec->chip_name = newname;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_set_chip_name);
+
+/**
+ * snd_hdac_codec_modalias - give the module alias name
+ * @codec: HDAC device
+ * @buf: string buffer to store
+ * @size: string buffer size
+ *
+ * Returns the size of string, like snprintf(), or a negative error code.
+ */
+int snd_hdac_codec_modalias(struct hdac_device *codec, char *buf, size_t size)
+{
+       return snprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n",
+                       codec->vendor_id, codec->revision_id, codec->type);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias);
+
 /**
  * snd_hdac_make_cmd - compose a 32bit command word to be sent to the
  *     HD-audio controller
@@ -592,8 +629,10 @@ int snd_hdac_power_down_pm(struct hdac_device *codec)
 EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
 #endif
 
-/*
- * Enable/disable the link power for a codec.
+/**
+ * snd_hdac_link_power - Enable/disable the link power for a codec
+ * @codec: the codec object
+ * @bool: enable or disable the link power
  */
 int snd_hdac_link_power(struct hdac_device *codec, bool enable)
 {
@@ -952,3 +991,84 @@ bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
        return true;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format);
+
+static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm)
+{
+       unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm);
+       unsigned int res;
+
+       if (snd_hdac_exec_verb(hdac, cmd, flags, &res))
+               return -1;
+
+       return res;
+}
+
+static int codec_write(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm)
+{
+       unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm);
+
+       return snd_hdac_exec_verb(hdac, cmd, flags, NULL);
+}
+
+/**
+ * snd_hdac_codec_read - send a command and get the response
+ * @hdac: the HDAC device
+ * @nid: NID to send the command
+ * @flags: optional bit flags
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command and read the corresponding response.
+ *
+ * Returns the obtained response value, or -1 for an error.
+ */
+int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm)
+{
+       return codec_read(hdac, nid, flags, verb, parm);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_read);
+
+/**
+ * snd_hdac_codec_write - send a single command without waiting for response
+ * @hdac: the HDAC device
+ * @nid: NID to send the command
+ * @flags: optional bit flags
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command without waiting for response.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
+                       int flags, unsigned int verb, unsigned int parm)
+{
+       return codec_write(hdac, nid, flags, verb, parm);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_write);
+
+/**
+ * snd_hdac_check_power_state - check whether the actual power state matches
+ * with the target state
+ *
+ * @hdac: the HDAC device
+ * @nid: NID to send the command
+ * @target_state: target state to check for
+ *
+ * Return true if state matches, false if not
+ */
+bool snd_hdac_check_power_state(struct hdac_device *hdac,
+               hda_nid_t nid, unsigned int target_state)
+{
+       unsigned int state = codec_read(hdac, nid, 0,
+                               AC_VERB_GET_POWER_STATE, 0);
+
+       if (state & AC_PWRST_ERROR)
+               return true;
+       state = (state >> 4) & 0x0f;
+       return (state == target_state);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_check_power_state);
index 55c3df4458f7936b56ceda126ce8f3a0f0b51abe..8fef1b8d1fd8acc443bc86a2aedd66763d9b84fd 100644 (file)
 
 static struct i915_audio_component *hdac_acomp;
 
+/**
+ * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
+ * @bus: HDA core bus
+ * @enable: enable or disable the wakeup
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function should be called during the chip reset, also called at
+ * resume for updating STATESTS register read.
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
 {
        struct i915_audio_component *acomp = bus->audio_component;
@@ -45,6 +58,19 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
 
+/**
+ * snd_hdac_display_power - Power up / down the power refcount
+ * @bus: HDA core bus
+ * @enable: power up or down
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function manages a refcount and calls the i915 get_power() and
+ * put_power() ops accordingly, toggling the codec wakeup, too.
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
 {
        struct i915_audio_component *acomp = bus->audio_component;
@@ -71,6 +97,16 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_display_power);
 
+/**
+ * snd_hdac_get_display_clk - Get CDCLK in kHz
+ * @bus: HDA core bus
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function queries CDCLK value in kHz from the graphics driver and
+ * returns the value.  A negative code is returned in error.
+ */
 int snd_hdac_get_display_clk(struct hdac_bus *bus)
 {
        struct i915_audio_component *acomp = bus->audio_component;
@@ -134,6 +170,17 @@ static int hdac_component_master_match(struct device *dev, void *data)
        return !strcmp(dev->driver->name, "i915");
 }
 
+/**
+ * snd_hdac_i915_register_notifier - Register i915 audio component ops
+ * @aops: i915 audio component ops
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function sets the given ops to be called by the i915 graphics driver.
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
 {
        if (WARN_ON(!hdac_acomp))
@@ -144,6 +191,18 @@ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops
 }
 EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
 
+/**
+ * snd_hdac_i915_init - Initialize i915 audio component
+ * @bus: HDA core bus
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function initializes and sets up the audio component to communicate
+ * with i915 graphics driver.
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_i915_init(struct hdac_bus *bus)
 {
        struct component_match *match = NULL;
@@ -187,6 +246,17 @@ out_err:
 }
 EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
 
+/**
+ * snd_hdac_i915_exit - Finalize i915 audio component
+ * @bus: HDA core bus
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function releases the i915 audio component that has been used.
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_i915_exit(struct hdac_bus *bus)
 {
        struct device *dev = bus->dev;
index b0ed870ffb88eda0cc47e4c748488f314429375d..eb8f7c30cb0941275ebd495ee41467a0171e3562 100644 (file)
@@ -339,6 +339,12 @@ static const struct regmap_config hda_regmap_cfg = {
        .use_single_rw = true,
 };
 
+/**
+ * snd_hdac_regmap_init - Initialize regmap for HDA register accesses
+ * @codec: the codec object
+ *
+ * Returns zero for success or a negative error code.
+ */
 int snd_hdac_regmap_init(struct hdac_device *codec)
 {
        struct regmap *regmap;
@@ -352,6 +358,10 @@ int snd_hdac_regmap_init(struct hdac_device *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
 
+/**
+ * snd_hdac_regmap_init - Release the regmap from HDA codec
+ * @codec: the codec object
+ */
 void snd_hdac_regmap_exit(struct hdac_device *codec)
 {
        if (codec->regmap) {
index 8981159813efb7e361d78d8f26bf032b0565f00b..38990a77d7b780081167fa14ded35745025553c1 100644 (file)
@@ -426,7 +426,8 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
 
-/* snd_hdac_stream_set_params - set stream parameters
+/**
+ * snd_hdac_stream_set_params - set stream parameters
  * @azx_dev: HD-audio core stream for which parameters are to be set
  * @format_val: format value parameter
  *
index c71142dea98a18f5355f1395c4c34200a773c52e..42d61bf41969c2176f1e10842e0c8e651d202a23 100644 (file)
@@ -45,6 +45,13 @@ CODEC_ATTR(mfg);
 CODEC_ATTR_STR(vendor_name);
 CODEC_ATTR_STR(chip_name);
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       return snd_hdac_codec_modalias(dev_to_hdac_dev(dev), buf, 256);
+}
+static DEVICE_ATTR_RO(modalias);
+
 static struct attribute *hdac_dev_attrs[] = {
        &dev_attr_type.attr,
        &dev_attr_vendor_id.attr,
@@ -54,6 +61,7 @@ static struct attribute *hdac_dev_attrs[] = {
        &dev_attr_mfg.attr,
        &dev_attr_vendor_name.attr,
        &dev_attr_chip_name.attr,
+       &dev_attr_modalias.attr,
        NULL
 };
 
index 2a9f4a345171ee6b521c7c153f19991c40381f33..2706f271a83b0f19cf7a83b833b9f4e3a35e4242 100644 (file)
@@ -1864,7 +1864,7 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
        /* global setup */
        pcm->info_flags = 0;
        strcpy(pcm->name, "CS46xx - IEC958");
-       chip->pcm_rear = pcm;
+       chip->pcm_iec958 = pcm;
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
@@ -2528,7 +2528,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->nr_ac97_codecs == 1) {
                unsigned int id2 = chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]->id & 0xffff;
-               if (id2 == 0x592b || id2 == 0x592d) {
+               if ((id2 & 0xfff0) == 0x5920) { /* CS4294 and CS4298 */
                        err = snd_ctl_add(card, snd_ctl_new1(&snd_cs46xx_front_dup_ctl, chip));
                        if (err < 0)
                                return err;
@@ -3780,6 +3780,11 @@ static int snd_cs46xx_suspend(struct device *dev)
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->in_suspend = 1;
        snd_pcm_suspend_all(chip->pcm);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+       snd_pcm_suspend_all(chip->pcm_rear);
+       snd_pcm_suspend_all(chip->pcm_center_lfe);
+       snd_pcm_suspend_all(chip->pcm_iec958);
+#endif
        // chip->ac97_powerdown = snd_cs46xx_codec_read(chip, AC97_POWER_CONTROL);
        // chip->ac97_general_purpose = snd_cs46xx_codec_read(chip, BA0_AC97_GENERAL_PURPOSE);
 
index d5ac25cc7fee1fbc87b577da634f9f13706091a5..70671ad65d24565fb6c8522bd69444817aac2933 100644 (file)
 #include "hda_local.h"
 
 /*
- * find a matching codec preset
+ * find a matching codec id
  */
 static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
 {
        struct hda_codec *codec = container_of(dev, struct hda_codec, core);
        struct hda_codec_driver *driver =
                container_of(drv, struct hda_codec_driver, core);
-       const struct hda_codec_preset *preset;
+       const struct hda_device_id *list;
        /* check probe_id instead of vendor_id if set */
        u32 id = codec->probe_id ? codec->probe_id : codec->core.vendor_id;
+       u32 rev_id = codec->core.revision_id;
 
-       for (preset = driver->preset; preset->id; preset++) {
-               if (preset->id == id &&
-                   (!preset->rev || preset->rev == codec->core.revision_id)) {
-                       codec->preset = preset;
+       for (list = driver->id; list->vendor_id; list++) {
+               if (list->vendor_id == id &&
+                   (!list->rev_id || list->rev_id == rev_id)) {
+                       codec->preset = list;
                        return 1;
                }
        }
@@ -45,26 +46,45 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
                codec->patch_ops.unsol_event(codec, ev);
 }
 
-/* reset the codec name from the preset */
-static int codec_refresh_name(struct hda_codec *codec, const char *name)
+/**
+ * snd_hda_codec_set_name - set the codec name
+ * @codec: the HDA codec
+ * @name: name string to set
+ */
+int snd_hda_codec_set_name(struct hda_codec *codec, const char *name)
 {
-       if (name) {
-               kfree(codec->core.chip_name);
-               codec->core.chip_name = kstrdup(name, GFP_KERNEL);
+       int err;
+
+       if (!name)
+               return 0;
+       err = snd_hdac_device_set_chip_name(&codec->core, name);
+       if (err < 0)
+               return err;
+
+       /* update the mixer name */
+       if (!*codec->card->mixername ||
+           codec->bus->mixer_assigned >= codec->core.addr) {
+               snprintf(codec->card->mixername,
+                        sizeof(codec->card->mixername), "%s %s",
+                        codec->core.vendor_name, codec->core.chip_name);
+               codec->bus->mixer_assigned = codec->core.addr;
        }
-       return codec->core.chip_name ? 0 : -ENOMEM;
+
+       return 0;
 }
+EXPORT_SYMBOL_GPL(snd_hda_codec_set_name);
 
 static int hda_codec_driver_probe(struct device *dev)
 {
        struct hda_codec *codec = dev_to_hda_codec(dev);
        struct module *owner = dev->driver->owner;
+       hda_codec_patch_t patch;
        int err;
 
        if (WARN_ON(!codec->preset))
                return -EINVAL;
 
-       err = codec_refresh_name(codec, codec->preset->name);
+       err = snd_hda_codec_set_name(codec, codec->preset->name);
        if (err < 0)
                goto error;
        err = snd_hdac_regmap_init(&codec->core);
@@ -76,9 +96,12 @@ static int hda_codec_driver_probe(struct device *dev)
                goto error;
        }
 
-       err = codec->preset->patch(codec);
-       if (err < 0)
-               goto error_module;
+       patch = (hda_codec_patch_t)codec->preset->driver_data;
+       if (patch) {
+               err = patch(codec);
+               if (err < 0)
+                       goto error_module;
+       }
 
        err = snd_hda_codec_build_pcms(codec);
        if (err < 0)
@@ -155,11 +178,10 @@ static inline bool codec_probed(struct hda_codec *codec)
 static void codec_bind_module(struct hda_codec *codec)
 {
 #ifdef MODULE
-       request_module("snd-hda-codec-id:%08x", codec->core.vendor_id);
-       if (codec_probed(codec))
-               return;
-       request_module("snd-hda-codec-id:%04x*",
-                      (codec->core.vendor_id >> 16) & 0xffff);
+       char modalias[32];
+
+       snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
+       request_module(modalias);
        if (codec_probed(codec))
                return;
 #endif
@@ -251,11 +273,6 @@ int snd_hda_codec_configure(struct hda_codec *codec)
                }
        }
 
-       /* audio codec should override the mixer name */
-       if (codec->core.afg || !*codec->card->mixername)
-               snprintf(codec->card->mixername,
-                        sizeof(codec->card->mixername), "%s %s",
-                        codec->core.vendor_name, codec->core.chip_name);
        return 0;
 
  error:
index a249d5486889dca683af566e0818d95ee49b12ae..83741887faa189c1700abc34bebbd3c55234384d 100644 (file)
@@ -90,50 +90,6 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd,
        return err;
 }
 
-/**
- * snd_hda_codec_read - send a command and get the response
- * @codec: the HDA codec
- * @nid: NID to send the command
- * @flags: optional bit flags
- * @verb: the verb to send
- * @parm: the parameter for the verb
- *
- * Send a single command and read the corresponding response.
- *
- * Returns the obtained response value, or -1 for an error.
- */
-unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
-                               int flags,
-                               unsigned int verb, unsigned int parm)
-{
-       unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm);
-       unsigned int res;
-       if (snd_hdac_exec_verb(&codec->core, cmd, flags, &res))
-               return -1;
-       return res;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_read);
-
-/**
- * snd_hda_codec_write - send a single command without waiting for response
- * @codec: the HDA codec
- * @nid: NID to send the command
- * @flags: optional bit flags
- * @verb: the verb to send
- * @parm: the parameter for the verb
- *
- * Send a single command without waiting for response.
- *
- * Returns 0 if successful, or a negative error code.
- */
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
-                       unsigned int verb, unsigned int parm)
-{
-       unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm);
-       return snd_hdac_exec_verb(&codec->core, cmd, flags, NULL);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_write);
-
 /**
  * snd_hda_sequence_write - sequence writes
  * @codec: the HDA codec
index 2970413f18a01817b9500ed7f1c00f61e3b1e92b..373fcad840ea6ff5c18b4c4aa93b6473c7a60f1c 100644 (file)
@@ -22,6 +22,7 @@
 #define __SOUND_HDA_CODEC_H
 
 #include <linux/kref.h>
+#include <linux/mod_devicetable.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -69,6 +70,7 @@ struct hda_bus {
        unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
 
        int primary_dig_out_type;       /* primary digital out PCM type */
+       unsigned int mixer_assigned;    /* codec addr for mixer name */
 };
 
 /* from hdac_bus to hda_bus */
@@ -80,19 +82,21 @@ struct hda_bus {
  * Known codecs have the patch to build and set up the controls/PCMs
  * better than the generic parser.
  */
-struct hda_codec_preset {
-       unsigned int id;
-       unsigned int rev;
-       const char *name;
-       int (*patch)(struct hda_codec *codec);
-};
+typedef int (*hda_codec_patch_t)(struct hda_codec *);
        
 #define HDA_CODEC_ID_GENERIC_HDMI      0x00000101
 #define HDA_CODEC_ID_GENERIC           0x00000201
 
+#define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \
+       { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
+         .api_version = HDA_DEV_LEGACY, \
+         .driver_data = (unsigned long)(_patch) }
+#define HDA_CODEC_ENTRY(_vid, _name, _patch) \
+       HDA_CODEC_REV_ENTRY(_vid, 0, _name, _patch)
+
 struct hda_codec_driver {
        struct hdac_driver core;
-       const struct hda_codec_preset *preset;
+       const struct hda_device_id *id;
 };
 
 int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
@@ -183,7 +187,7 @@ struct hda_codec {
        u32 probe_id; /* overridden id for probing */
 
        /* detected preset */
-       const struct hda_codec_preset *preset;
+       const struct hda_device_id *preset;
        const char *modelname;  /* model name for preset */
 
        /* set by patch */
@@ -297,10 +301,6 @@ struct hda_codec {
 /*
  * constructors
  */
-int snd_hda_bus_new(struct snd_card *card,
-                   const struct hdac_bus_ops *ops,
-                   const struct hdac_io_ops *io_ops,
-                   struct hda_bus **busp);
 int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                      unsigned int codec_addr, struct hda_codec **codecp);
 int snd_hda_codec_configure(struct hda_codec *codec);
@@ -309,11 +309,21 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec);
 /*
  * low level functions
  */
-unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
+static inline unsigned int
+snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
                                int flags,
-                               unsigned int verb, unsigned int parm);
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
-                       unsigned int verb, unsigned int parm);
+                               unsigned int verb, unsigned int parm)
+{
+       return snd_hdac_codec_read(&codec->core, nid, flags, verb, parm);
+}
+
+static inline int
+snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
+                       unsigned int verb, unsigned int parm)
+{
+       return snd_hdac_codec_write(&codec->core, nid, flags, verb, parm);
+}
+
 #define snd_hda_param_read(codec, nid, param) \
        snd_hdac_read_parm(&(codec)->core, nid, param)
 #define snd_hda_get_sub_nodes(codec, nid, start_nid) \
@@ -453,6 +463,8 @@ void snd_hda_unlock_devices(struct hda_bus *bus);
 void snd_hda_bus_reset(struct hda_bus *bus);
 void snd_hda_bus_reset_codecs(struct hda_bus *bus);
 
+int snd_hda_codec_set_name(struct hda_codec *codec, const char *name);
+
 /*
  * power management
  */
index 944455997fdcc8fd80758b4fb5794488543bd966..22dbfa563919fca4ace4d3d50b7c822008c7bb34 100644 (file)
@@ -1045,6 +1045,7 @@ int azx_bus_init(struct azx *chip, const char *model,
        mutex_init(&bus->prepare_mutex);
        bus->pci = chip->pci;
        bus->modelname = model;
+       bus->mixer_assigned = -1;
        bus->core.snoop = azx_snoop(chip);
        if (chip->get_position[0] != azx_get_pos_lpib ||
            chip->get_position[1] != azx_get_pos_lpib)
@@ -1059,6 +1060,9 @@ int azx_bus_init(struct azx *chip, const char *model,
                bus->needs_damn_long_delay = 1;
        }
 
+       if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
+               bus->core.align_bdle_4k = true;
+
        /* AMD chipsets often cause the communication stalls upon certain
         * sequence like the pin-detection.  It seems that forcing the synced
         * access works around the stall.  Grrr...
index 24f91114a32cc73f54d72d8b008db51935519893..c6e8a651cea1357df06a2934d1854c926f6e50c4 100644 (file)
@@ -5877,13 +5877,14 @@ error:
        return err;
 }
 
-static const struct hda_codec_preset snd_hda_preset_generic[] = {
-       { .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec },
+static const struct hda_device_id snd_hda_id_generic[] = {
+       HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
        {} /* terminator */
 };
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
 
 static struct hda_codec_driver generic_driver = {
-       .preset = snd_hda_preset_generic,
+       .id = snd_hda_id_generic,
 };
 
 module_hda_codec_driver(generic_driver);
index c38c68f579381d657786945baa3ab99b3ccae787..4d2cbe2ca14183561d80319cd37f717149083047 100644 (file)
@@ -334,6 +334,7 @@ enum {
 
 #define AZX_DCAPS_PRESET_CTHDA \
        (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\
+        AZX_DCAPS_NO_64BIT |\
         AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
 
 /*
@@ -2104,6 +2105,11 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        { PCI_DEVICE(0x8086, 0x8d21),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       /* Lewisburg */
+       { PCI_DEVICE(0x8086, 0xa1f0),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE(0x8086, 0xa270),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Lynx Point-LP */
        { PCI_DEVICE(0x8086, 0x9c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -2284,11 +2290,13 @@ static const struct pci_device_id azx_ids[] = {
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_NO_64BIT |
          AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
        { PCI_DEVICE(0x1102, 0x0009),
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_NO_64BIT |
          AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
        /* CM8888 */
index 4a21c2199e0219d980a69d82a83bd91942c22f83..d0e066e4c9856028b1f9cbc0faeb3dc2e3a5ae9a 100644 (file)
@@ -681,12 +681,7 @@ static inline bool
 snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
                          unsigned int target_state)
 {
-       unsigned int state = snd_hda_codec_read(codec, nid, 0,
-                                               AC_VERB_GET_POWER_STATE, 0);
-       if (state & AC_PWRST_ERROR)
-               return true;
-       state = (state >> 4) & 0x0f;
-       return (state == target_state);
+       return snd_hdac_check_power_state(&codec->core, nid, target_state);
 }
 
 unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
index a6e3d9b511ab5f0a2bfa446cbb004c002b81f029..64e0d1d81ca5afd66625669079bdce05fa23dc63 100644 (file)
@@ -595,8 +595,7 @@ static void parse_model_mode(char *buf, struct hda_bus *bus,
 static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
                                 struct hda_codec **codecp)
 {
-       kfree((*codecp)->core.chip_name);
-       (*codecp)->core.chip_name = kstrdup(buf, GFP_KERNEL);
+       snd_hda_codec_set_name(*codecp, buf);
 }
 
 #define DEFINE_PARSE_ID_MODE(name) \
index c033a4ee65470fb592e77836437262063f00f125..e0fb8c6d1bc274e4ff5f6a8bf55afa9852bf9026 100644 (file)
@@ -1165,32 +1165,31 @@ static int patch_ad1882(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_analog[] = {
-       { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 },
-       { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
-       { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 },
-       { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
-       { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 },
-       { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 },
-       { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
-       { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
-       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 },
-       { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
-       { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
-       { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
-       { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
-       { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
-       { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
+static const struct hda_device_id snd_hda_id_analog[] = {
+       HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
+       HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
+       HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
+       HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
+       HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
+       HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:11d4*");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
 
 static struct hda_codec_driver analog_driver = {
-       .preset = snd_hda_preset_analog,
+       .id = snd_hda_id_analog,
 };
 
 module_hda_codec_driver(analog_driver);
index 484bbf4134cd127e8b9a9cf03bbc66ab361755f6..c2d9ee9cfdc00900aee82957fee356442710faa3 100644 (file)
@@ -83,22 +83,19 @@ static int patch_ca0110(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_ca0110[] = {
-       { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
-       { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
-       { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
+static const struct hda_device_id snd_hda_id_ca0110[] = {
+       HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110),
+       HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110),
+       HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:1102000a");
-MODULE_ALIAS("snd-hda-codec-id:1102000b");
-MODULE_ALIAS("snd-hda-codec-id:1102000d");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
 
 static struct hda_codec_driver ca0110_driver = {
-       .preset = snd_hda_preset_ca0110,
+       .id = snd_hda_id_ca0110,
 };
 
 module_hda_codec_driver(ca0110_driver);
index 186792fe226e08d95d8bb67c959e0fbd7d86bd25..f8a12ca477f1ab775a101c8bb41876a11707477e 100644 (file)
@@ -2673,13 +2673,13 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
 
        do {
                if (dspload_is_loaded(codec)) {
-                       pr_info("ca0132 DOWNLOAD OK :-) DSP IS RUNNING.\n");
+                       codec_info(codec, "ca0132 DSP downloaded and running\n");
                        return true;
                }
                msleep(20);
        } while (time_before(jiffies, timeout));
 
-       pr_err("ca0132 DOWNLOAD FAILED!!! DSP IS NOT RUNNING.\n");
+       codec_err(codec, "ca0132 failed to download DSP\n");
        return false;
 }
 
@@ -4375,7 +4375,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
 
        dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
        if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
-               pr_err("ca0132 dspload_image failed.\n");
+               codec_err(codec, "ca0132 DSP load image failed\n");
                goto exit_download;
        }
 
@@ -4778,18 +4778,17 @@ static int patch_ca0132(struct hda_codec *codec)
 /*
  * patch entries
  */
-static struct hda_codec_preset snd_hda_preset_ca0132[] = {
-       { .id = 0x11020011, .name = "CA0132",     .patch = patch_ca0132 },
+static struct hda_device_id snd_hda_id_ca0132[] = {
+       HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:11020011");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative Sound Core3D codec");
 
 static struct hda_codec_driver ca0132_driver = {
-       .preset = snd_hda_preset_ca0132,
+       .id = snd_hda_id_ca0132,
 };
 
 module_hda_codec_driver(ca0132_driver);
index 85813de26da87715df7d1d259339e30450c7815a..a12ae8ac091451261a2ba613543677fabedb8cd0 100644 (file)
@@ -570,6 +570,7 @@ static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
                return NULL;
        codec->spec = spec;
        spec->vendor_nid = vendor_nid;
+       codec->power_save_node = 1;
        snd_hda_gen_spec_init(&spec->gen);
 
        return spec;
@@ -1200,26 +1201,21 @@ static int patch_cs4213(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
-       { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
-       { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
-       { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 },
-       { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 },
-       { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 },
+static const struct hda_device_id snd_hda_id_cirrus[] = {
+       HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
+       HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
+       HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
+       HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
+       HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:10134206");
-MODULE_ALIAS("snd-hda-codec-id:10134207");
-MODULE_ALIAS("snd-hda-codec-id:10134208");
-MODULE_ALIAS("snd-hda-codec-id:10134210");
-MODULE_ALIAS("snd-hda-codec-id:10134213");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
 
 static struct hda_codec_driver cirrus_driver = {
-       .preset = snd_hda_preset_cirrus,
+       .id = snd_hda_id_cirrus,
 };
 
 module_hda_codec_driver(cirrus_driver);
index f5ed078710f8494918786657613180f1d75a2286..1b2195dd2b26588d8075f79b14636cef1ced47b3 100644 (file)
@@ -123,22 +123,19 @@ static int patch_cmi8888(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
-       { .id = 0x13f68888, .name = "CMI8888", .patch = patch_cmi8888 },
-       { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
-       { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
+static const struct hda_device_id snd_hda_id_cmedia[] = {
+       HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
+       HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
+       HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:13f68888");
-MODULE_ALIAS("snd-hda-codec-id:13f69880");
-MODULE_ALIAS("snd-hda-codec-id:434d4980");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("C-Media HD-audio codec");
 
 static struct hda_codec_driver cmedia_driver = {
-       .preset = snd_hda_preset_cmedia,
+       .id = snd_hda_id_cmedia,
 };
 
 module_hda_codec_driver(cmedia_driver);
index 2f0ec7c45fc70d6232339761e5773349d24213a9..c8b8ef5246a6f94c99b281c837e220e118dbf8a9 100644 (file)
@@ -954,100 +954,44 @@ static int patch_conexant_auto(struct hda_codec *codec)
 /*
  */
 
-static const struct hda_codec_preset snd_hda_preset_conexant[] = {
-       { .id = 0x14f15045, .name = "CX20549 (Venice)",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15047, .name = "CX20551 (Waikiki)",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15051, .name = "CX20561 (Hermosa)",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15066, .name = "CX20582 (Pebble)",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15068, .name = "CX20584",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15069, .name = "CX20585",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f1506c, .name = "CX20588",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f1506e, .name = "CX20590",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15097, .name = "CX20631",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15098, .name = "CX20632",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150a1, .name = "CX20641",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150a2, .name = "CX20642",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150ab, .name = "CX20651",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150ac, .name = "CX20652",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150b8, .name = "CX20664",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150b9, .name = "CX20665",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150f1, .name = "CX20721",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150f2, .name = "CX20722",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150f3, .name = "CX20723",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f150f4, .name = "CX20724",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f1510f, .name = "CX20751/2",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15110, .name = "CX20751/2",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15111, .name = "CX20753/4",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15113, .name = "CX20755",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15114, .name = "CX20756",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f15115, .name = "CX20757",
-         .patch = patch_conexant_auto },
-       { .id = 0x14f151d7, .name = "CX20952",
-         .patch = patch_conexant_auto },
+static const struct hda_device_id snd_hda_id_conexant[] = {
+       HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f1, "CX20721", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f3, "CX20723", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:14f15045");
-MODULE_ALIAS("snd-hda-codec-id:14f15047");
-MODULE_ALIAS("snd-hda-codec-id:14f15051");
-MODULE_ALIAS("snd-hda-codec-id:14f15066");
-MODULE_ALIAS("snd-hda-codec-id:14f15067");
-MODULE_ALIAS("snd-hda-codec-id:14f15068");
-MODULE_ALIAS("snd-hda-codec-id:14f15069");
-MODULE_ALIAS("snd-hda-codec-id:14f1506c");
-MODULE_ALIAS("snd-hda-codec-id:14f1506e");
-MODULE_ALIAS("snd-hda-codec-id:14f15097");
-MODULE_ALIAS("snd-hda-codec-id:14f15098");
-MODULE_ALIAS("snd-hda-codec-id:14f150a1");
-MODULE_ALIAS("snd-hda-codec-id:14f150a2");
-MODULE_ALIAS("snd-hda-codec-id:14f150ab");
-MODULE_ALIAS("snd-hda-codec-id:14f150ac");
-MODULE_ALIAS("snd-hda-codec-id:14f150b8");
-MODULE_ALIAS("snd-hda-codec-id:14f150b9");
-MODULE_ALIAS("snd-hda-codec-id:14f150f1");
-MODULE_ALIAS("snd-hda-codec-id:14f150f2");
-MODULE_ALIAS("snd-hda-codec-id:14f150f3");
-MODULE_ALIAS("snd-hda-codec-id:14f150f4");
-MODULE_ALIAS("snd-hda-codec-id:14f1510f");
-MODULE_ALIAS("snd-hda-codec-id:14f15110");
-MODULE_ALIAS("snd-hda-codec-id:14f15111");
-MODULE_ALIAS("snd-hda-codec-id:14f15113");
-MODULE_ALIAS("snd-hda-codec-id:14f15114");
-MODULE_ALIAS("snd-hda-codec-id:14f15115");
-MODULE_ALIAS("snd-hda-codec-id:14f151d7");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
 
 static struct hda_codec_driver conexant_driver = {
-       .preset = snd_hda_preset_conexant,
+       .id = snd_hda_id_conexant,
 };
 
 module_hda_codec_driver(conexant_driver);
index acbfbe087ee86d41f5688b0af85c4ee6f7eec43f..f503a883bef31d0fd55a38dd816f70609edcaf82 100644 (file)
@@ -1775,6 +1775,16 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
        return non_pcm;
 }
 
+/* There is a fixed mapping between audio pin node and display port
+ * on current Intel platforms:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_pin2port(hda_nid_t pin_nid)
+{
+       return pin_nid - 4;
+}
 
 /*
  * HDMI callbacks
@@ -1791,6 +1801,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        int pin_idx = hinfo_to_pin_index(codec, hinfo);
        struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct i915_audio_component *acomp = codec->bus->core.audio_component;
        bool non_pcm;
        int pinctl;
 
@@ -1807,6 +1819,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx);
        }
 
+       /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
+       /* Todo: add DP1.2 MST audio support later */
+       if (acomp && acomp->ops && acomp->ops->sync_audio_rate)
+               acomp->ops->sync_audio_rate(acomp->dev,
+                               intel_pin2port(pin_nid),
+                               runtime->rate);
+
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
        mutex_lock(&per_pin->lock);
        per_pin->channels = substream->runtime->channels;
@@ -2561,7 +2580,7 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
        struct hdmi_spec *spec = codec->spec;
        struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
 
-       switch (codec->preset->id) {
+       switch (codec->preset->vendor_id) {
        case 0x10de0002:
        case 0x10de0003:
        case 0x10de0005:
@@ -2879,7 +2898,7 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
                                     snd_pcm_alt_chmaps, 8, 0, &chmap);
        if (err < 0)
                return err;
-       switch (codec->preset->id) {
+       switch (codec->preset->vendor_id) {
        case 0x10de0002:
        case 0x10de0003:
        case 0x10de0005:
@@ -3487,138 +3506,77 @@ static int patch_via_hdmi(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
-{ .id = 0x1002793c, .name = "RS600 HDMI",      .patch = patch_atihdmi },
-{ .id = 0x10027919, .name = "RS600 HDMI",      .patch = patch_atihdmi },
-{ .id = 0x1002791a, .name = "RS690/780 HDMI",  .patch = patch_atihdmi },
-{ .id = 0x1002aa01, .name = "R6xx HDMI",       .patch = patch_atihdmi },
-{ .id = 0x10951390, .name = "SiI1390 HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x10951392, .name = "SiI1392 HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x17e80047, .name = "Chrontel HDMI",   .patch = patch_generic_hdmi },
-{ .id = 0x10de0002, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de0003, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de0005, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de0006, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de0007, .name = "MCP79/7A HDMI",   .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de000c, .name = "MCP89 HDMI",      .patch = patch_nvhdmi },
-{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",  .patch = patch_nvhdmi },
+static const struct hda_device_id snd_hda_id_hdmi[] = {
+HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",      patch_atihdmi),
+HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",      patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",  patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",       patch_atihdmi),
+HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",      patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",  patch_nvhdmi),
 /* 17 is known to be absent */
-{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0020, .name = "Tegra30 HDMI",    .patch = patch_tegra_hdmi },
-{ .id = 0x10de0022, .name = "Tegra114 HDMI",   .patch = patch_tegra_hdmi },
-{ .id = 0x10de0028, .name = "Tegra124 HDMI",   .patch = patch_tegra_hdmi },
-{ .id = 0x10de0029, .name = "Tegra210 HDMI/DP",        .patch = patch_tegra_hdmi },
-{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0067, .name = "MCP67 HDMI",      .patch = patch_nvhdmi_2ch },
-{ .id = 0x10de0070, .name = "GPU 70 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0071, .name = "GPU 71 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de0072, .name = "GPU 72 HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de007d, .name = "GPU 7d HDMI/DP",  .patch = patch_nvhdmi },
-{ .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
-{ .id = 0x11069f80, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
-{ .id = 0x11069f81, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
-{ .id = 0x11069f84, .name = "VX11 HDMI/DP",    .patch = patch_generic_hdmi },
-{ .id = 0x11069f85, .name = "VX11 HDMI/DP",    .patch = patch_generic_hdmi },
-{ .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
-{ .id = 0x80862801, .name = "Bearlake HDMI",   .patch = patch_generic_hdmi },
-{ .id = 0x80862802, .name = "Cantiga HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x80862803, .name = "Eaglelake HDMI",  .patch = patch_generic_hdmi },
-{ .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
-{ .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_generic_hdmi },
-{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
-{ .id = 0x80862807, .name = "Haswell HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x80862808, .name = "Broadwell HDMI",  .patch = patch_generic_hdmi },
-{ .id = 0x80862809, .name = "Skylake HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x8086280a, .name = "Broxton HDMI",    .patch = patch_generic_hdmi },
-{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
-{ .id = 0x80862882, .name = "Valleyview2 HDMI",        .patch = patch_generic_hdmi },
-{ .id = 0x80862883, .name = "Braswell HDMI",   .patch = patch_generic_hdmi },
-{ .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_generic_hdmi },
+HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",    patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",   patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",   patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",        patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",   patch_via_hdmi),
+HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",   patch_via_hdmi),
+HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",  patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",        patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",  patch_generic_hdmi),
 /* special ID for generic HDMI */
-{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi },
+HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
 {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:1002793c");
-MODULE_ALIAS("snd-hda-codec-id:10027919");
-MODULE_ALIAS("snd-hda-codec-id:1002791a");
-MODULE_ALIAS("snd-hda-codec-id:1002aa01");
-MODULE_ALIAS("snd-hda-codec-id:10951390");
-MODULE_ALIAS("snd-hda-codec-id:10951392");
-MODULE_ALIAS("snd-hda-codec-id:10de0002");
-MODULE_ALIAS("snd-hda-codec-id:10de0003");
-MODULE_ALIAS("snd-hda-codec-id:10de0005");
-MODULE_ALIAS("snd-hda-codec-id:10de0006");
-MODULE_ALIAS("snd-hda-codec-id:10de0007");
-MODULE_ALIAS("snd-hda-codec-id:10de000a");
-MODULE_ALIAS("snd-hda-codec-id:10de000b");
-MODULE_ALIAS("snd-hda-codec-id:10de000c");
-MODULE_ALIAS("snd-hda-codec-id:10de000d");
-MODULE_ALIAS("snd-hda-codec-id:10de0010");
-MODULE_ALIAS("snd-hda-codec-id:10de0011");
-MODULE_ALIAS("snd-hda-codec-id:10de0012");
-MODULE_ALIAS("snd-hda-codec-id:10de0013");
-MODULE_ALIAS("snd-hda-codec-id:10de0014");
-MODULE_ALIAS("snd-hda-codec-id:10de0015");
-MODULE_ALIAS("snd-hda-codec-id:10de0016");
-MODULE_ALIAS("snd-hda-codec-id:10de0018");
-MODULE_ALIAS("snd-hda-codec-id:10de0019");
-MODULE_ALIAS("snd-hda-codec-id:10de001a");
-MODULE_ALIAS("snd-hda-codec-id:10de001b");
-MODULE_ALIAS("snd-hda-codec-id:10de001c");
-MODULE_ALIAS("snd-hda-codec-id:10de0028");
-MODULE_ALIAS("snd-hda-codec-id:10de0040");
-MODULE_ALIAS("snd-hda-codec-id:10de0041");
-MODULE_ALIAS("snd-hda-codec-id:10de0042");
-MODULE_ALIAS("snd-hda-codec-id:10de0043");
-MODULE_ALIAS("snd-hda-codec-id:10de0044");
-MODULE_ALIAS("snd-hda-codec-id:10de0051");
-MODULE_ALIAS("snd-hda-codec-id:10de0060");
-MODULE_ALIAS("snd-hda-codec-id:10de0067");
-MODULE_ALIAS("snd-hda-codec-id:10de0070");
-MODULE_ALIAS("snd-hda-codec-id:10de0071");
-MODULE_ALIAS("snd-hda-codec-id:10de0072");
-MODULE_ALIAS("snd-hda-codec-id:10de007d");
-MODULE_ALIAS("snd-hda-codec-id:10de8001");
-MODULE_ALIAS("snd-hda-codec-id:11069f80");
-MODULE_ALIAS("snd-hda-codec-id:11069f81");
-MODULE_ALIAS("snd-hda-codec-id:11069f84");
-MODULE_ALIAS("snd-hda-codec-id:11069f85");
-MODULE_ALIAS("snd-hda-codec-id:17e80047");
-MODULE_ALIAS("snd-hda-codec-id:80860054");
-MODULE_ALIAS("snd-hda-codec-id:80862801");
-MODULE_ALIAS("snd-hda-codec-id:80862802");
-MODULE_ALIAS("snd-hda-codec-id:80862803");
-MODULE_ALIAS("snd-hda-codec-id:80862804");
-MODULE_ALIAS("snd-hda-codec-id:80862805");
-MODULE_ALIAS("snd-hda-codec-id:80862806");
-MODULE_ALIAS("snd-hda-codec-id:80862807");
-MODULE_ALIAS("snd-hda-codec-id:80862808");
-MODULE_ALIAS("snd-hda-codec-id:80862809");
-MODULE_ALIAS("snd-hda-codec-id:8086280a");
-MODULE_ALIAS("snd-hda-codec-id:80862880");
-MODULE_ALIAS("snd-hda-codec-id:80862882");
-MODULE_ALIAS("snd-hda-codec-id:80862883");
-MODULE_ALIAS("snd-hda-codec-id:808629fb");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("HDMI HD-audio codec");
@@ -3627,7 +3585,7 @@ MODULE_ALIAS("snd-hda-codec-nvhdmi");
 MODULE_ALIAS("snd-hda-codec-atihdmi");
 
 static struct hda_codec_driver hdmi_driver = {
-       .preset = snd_hda_preset_hdmi,
+       .id = snd_hda_id_hdmi,
 };
 
 module_hda_codec_driver(hdmi_driver);
index 16b8dcba5c12d2d13ed7c80c4e6f93df69d9944f..2f7b065f9ac43e88ee19b6845506c066485c679a 100644 (file)
@@ -822,17 +822,7 @@ static const struct hda_codec_ops alc_patch_ops = {
 };
 
 
-/* replace the codec chip_name with the given string */
-static int alc_codec_rename(struct hda_codec *codec, const char *name)
-{
-       kfree(codec->core.chip_name);
-       codec->core.chip_name = kstrdup(name, GFP_KERNEL);
-       if (!codec->core.chip_name) {
-               alc_free(codec);
-               return -ENOMEM;
-       }
-       return 0;
-}
+#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
 
 /*
  * Rename codecs appropriately from COEF value or subvendor id
@@ -4596,6 +4586,7 @@ enum {
        ALC292_FIXUP_DELL_E7X,
        ALC292_FIXUP_DISABLE_AAMIX,
        ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC275_FIXUP_DELL_XPS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5165,6 +5156,17 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE
        },
+       [ALC275_FIXUP_DELL_XPS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1f},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x00c0},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x30},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x00b1},
+                       {}
+               }
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5179,6 +5181,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
        SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
        SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
@@ -6627,78 +6630,70 @@ static int patch_alc680(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_realtek[] = {
-       { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
-       { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 },
-       { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 },
-       { .id = 0x10ec0235, .name = "ALC233", .patch = patch_alc269 },
-       { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 },
-       { .id = 0x10ec0256, .name = "ALC256", .patch = patch_alc269 },
-       { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
-       { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
-       { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
-       { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
-       { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
-       { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
-       { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
-       { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
-       { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
-       { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
-       { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
-       { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
-       { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
-       { .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 },
-       { .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 },
-       { .id = 0x10ec0288, .name = "ALC288", .patch = patch_alc269 },
-       { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
-       { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
-       { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 },
-       { .id = 0x10ec0298, .name = "ALC298", .patch = patch_alc269 },
-       { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
-         .patch = patch_alc861 },
-       { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
-       { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
-       { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
-       { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
-         .patch = patch_alc882 },
-       { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
-         .patch = patch_alc662 },
-       { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
-         .patch = patch_alc662 },
-       { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
-       { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
-       { .id = 0x10ec0667, .name = "ALC667", .patch = patch_alc662 },
-       { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
-       { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
-       { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 },
-       { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
-       { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 },
-       { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
-       { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
-       { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
-       { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
-         .patch = patch_alc882 },
-       { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
-         .patch = patch_alc882 },
-       { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
-       { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
-       { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
-         .patch = patch_alc882 },
-       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
-       { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
-       { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
-       { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
-       { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 },
+static const struct hda_device_id snd_hda_id_realtek[] = {
+       HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
+       HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
+       HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
+       HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
+       HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
+       HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
+       HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
+       HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
+       HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
+       HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
+       HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:10ec*");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek HD-audio codec");
 
 static struct hda_codec_driver realtek_driver = {
-       .preset = snd_hda_preset_realtek,
+       .id = snd_hda_id_realtek,
 };
 
 module_hda_codec_driver(realtek_driver);
index 5104bebb228699f1a04e754429f57e31622a521a..ffda38c45509583dd9e43f5f119c5d835b23e05b 100644 (file)
@@ -289,41 +289,30 @@ static int patch_si3054(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_si3054[] = {
-       { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+static const struct hda_device_id snd_hda_id_si3054[] = {
+       HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054),
        /* VIA HDA on Clevo m540 */
-       { .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 },
+       HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054),
        /* Asus A8J Modem (SM56) */
-       { .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 },
+       HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054),
        /* LG LW20 modem */
-       { .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 },
+       HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054),
        {}
 };
-
-MODULE_ALIAS("snd-hda-codec-id:163c3055");
-MODULE_ALIAS("snd-hda-codec-id:163c3155");
-MODULE_ALIAS("snd-hda-codec-id:11c13026");
-MODULE_ALIAS("snd-hda-codec-id:11c13055");
-MODULE_ALIAS("snd-hda-codec-id:11c13155");
-MODULE_ALIAS("snd-hda-codec-id:10573055");
-MODULE_ALIAS("snd-hda-codec-id:10573057");
-MODULE_ALIAS("snd-hda-codec-id:10573155");
-MODULE_ALIAS("snd-hda-codec-id:11063288");
-MODULE_ALIAS("snd-hda-codec-id:15433155");
-MODULE_ALIAS("snd-hda-codec-id:18540018");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
 
 static struct hda_codec_driver si3054_driver = {
-       .preset = snd_hda_preset_si3054,
+       .id = snd_hda_id_si3054,
 };
 
 module_hda_codec_driver(si3054_driver);
index def5cc8dff0293c2f70c4c3fcf67da1aea1bf55e..826122d8aceec4a931e64e99875dcd8cef661736 100644 (file)
@@ -702,6 +702,7 @@ static bool hp_bnb2011_with_dock(struct hda_codec *codec)
 static bool hp_blike_system(u32 subsystem_id)
 {
        switch (subsystem_id) {
+       case 0x103c1473: /* HP ProBook 6550b */
        case 0x103c1520:
        case 0x103c1521:
        case 0x103c1523:
@@ -5012,121 +5013,119 @@ static int patch_stac9872(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
-       { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
-       { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
-       { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
-       { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
-       { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
-       { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
-       { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
-       { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
-       { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
-       { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
-       { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
-       { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
-       { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
-       { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
-       { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
-       { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
-       { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
-       { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
-       { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
-       { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
-       { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
-       { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
-       { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
-       { .id = 0x83847632, .name = "STAC9202",  .patch = patch_stac925x },
-       { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
-       { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
-       { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
-       { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
-       { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
-       { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
-       { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
-       /* The following does not take into account .id=0x83847661 when subsys =
-        * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
-        * currently not fully supported.
-        */
-       { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
-       { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
-       { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
-       { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
-       { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
-       { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
-       { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
-       { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
-       { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
-       { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
-       { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
-       { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
-       { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
-       { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
-       { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
-       { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
-       { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
-       { .id = 0x111d7695, .name = "92HD95", .patch = patch_stac92hd95 },
-       { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
-       { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
-       { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx},
-       { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx},
+static const struct hda_device_id snd_hda_id_sigmatel[] = {
+       HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200),
+       HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847632, "STAC9202",  patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x),
+       /* The following does not take into account .id=0x83847661 when subsys =
+        * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
+        * currently not fully supported.
+        */
+       HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95),
+       HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:8384*");
-MODULE_ALIAS("snd-hda-codec-id:111d*");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
 
 static struct hda_codec_driver sigmatel_driver = {
-       .preset = snd_hda_preset_sigmatel,
+       .id = snd_hda_id_sigmatel,
 };
 
 module_hda_codec_driver(sigmatel_driver);
index da5366405eda55a6eccbca0e14bce5631c851cdc..fc30d1e8aa76a6b2aa9ca1de992b5a1c937bb971 100644 (file)
@@ -785,21 +785,11 @@ static int patch_vt1708S(struct hda_codec *codec)
        override_mic_boost(codec, 0x1e, 0, 3, 40);
 
        /* correct names for VT1708BCE */
-       if (get_codec_type(codec) == VT1708BCE) {
-               kfree(codec->core.chip_name);
-               codec->core.chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
-               snprintf(codec->card->mixername,
-                        sizeof(codec->card->mixername),
-                        "%s %s", codec->core.vendor_name, codec->core.chip_name);
-       }
+       if (get_codec_type(codec) == VT1708BCE)
+               snd_hda_codec_set_name(codec, "VT1708BCE");
        /* correct names for VT1705 */
-       if (codec->core.vendor_id == 0x11064397) {
-               kfree(codec->core.chip_name);
-               codec->core.chip_name = kstrdup("VT1705", GFP_KERNEL);
-               snprintf(codec->card->mixername,
-                        sizeof(codec->card->mixername),
-                        "%s %s", codec->core.vendor_name, codec->core.chip_name);
-       }
+       if (codec->core.vendor_id == 0x11064397)
+               snd_hda_codec_set_name(codec, "VT1705");
 
        /* automatic parse from the BIOS config */
        err = via_parse_auto_config(codec);
@@ -1210,109 +1200,64 @@ static int patch_vt3476(struct hda_codec *codec)
 /*
  * patch entries
  */
-static const struct hda_codec_preset snd_hda_preset_via[] = {
-       { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
-       { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
-       { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
-       { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
-       { .id = 0x1106e710, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e711, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e712, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e713, .name = "VT1709 10-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e714, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e715, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e716, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e717, .name = "VT1709 6-Ch",
-         .patch = patch_vt1709},
-       { .id = 0x1106e720, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e721, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e722, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e723, .name = "VT1708B 8-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e724, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e725, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e726, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x1106e727, .name = "VT1708B 4-Ch",
-         .patch = patch_vt1708B},
-       { .id = 0x11060397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11061397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11062397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11063397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11064397, .name = "VT1705",
-         .patch = patch_vt1708S},
-       { .id = 0x11065397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11066397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11067397, .name = "VT1708S",
-         .patch = patch_vt1708S},
-       { .id = 0x11060398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11061398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11062398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11063398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11064398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11065398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11066398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11067398, .name = "VT1702",
-         .patch = patch_vt1702},
-       { .id = 0x11060428, .name = "VT1718S",
-         .patch = patch_vt1718S},
-       { .id = 0x11064428, .name = "VT1718S",
-         .patch = patch_vt1718S},
-       { .id = 0x11060441, .name = "VT2020",
-         .patch = patch_vt1718S},
-       { .id = 0x11064441, .name = "VT1828S",
-         .patch = patch_vt1718S},
-       { .id = 0x11060433, .name = "VT1716S",
-         .patch = patch_vt1716S},
-       { .id = 0x1106a721, .name = "VT1716S",
-         .patch = patch_vt1716S},
-       { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
-       { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
-       { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
-       { .id = 0x11060440, .name = "VT1818S",
-         .patch = patch_vt1708S},
-       { .id = 0x11060446, .name = "VT1802",
-               .patch = patch_vt2002P},
-       { .id = 0x11068446, .name = "VT1802",
-               .patch = patch_vt2002P},
-       { .id = 0x11064760, .name = "VT1705CF",
-               .patch = patch_vt3476},
-       { .id = 0x11064761, .name = "VT1708SCE",
-               .patch = patch_vt3476},
-       { .id = 0x11064762, .name = "VT1808",
-               .patch = patch_vt3476},
+static const struct hda_device_id snd_hda_id_via[] = {
+       HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),
+       HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),
+       HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),
+       HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),
+       HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),
+       HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),
        {} /* terminator */
 };
-
-MODULE_ALIAS("snd-hda-codec-id:1106*");
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);
 
 static struct hda_codec_driver via_driver = {
-       .preset = snd_hda_preset_via,
+       .id = snd_hda_id_via,
 };
 
 MODULE_LICENSE("GPL");
index 7acbc21d642a53fe8658c52bdcf91992f08816ac..9e1ad119a3ce0430579d648ae34e6eedc3b7af10 100644 (file)
@@ -1394,7 +1394,9 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream)
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
-        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                    kPlayBufferFrames);
+
         return 0;
 }
 
@@ -1422,8 +1424,8 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream)
 
         spin_unlock_irqrestore(&korg1212->lock, flags);
 
-        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-                                    kPlayBufferFrames, kPlayBufferFrames);
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                    kPlayBufferFrames);
         return 0;
 }
 
index cba89beb2b38fac6e376a2231c1e4f68caa644e5..8b8e2e54fba3f1520d3ed6c6f22185274ca6ae5b 100644 (file)
@@ -234,8 +234,8 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
 
        /* the clock rate cannot be changed */
        board_rate = chip->board_sample_rate;
-       err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
-                                          board_rate, board_rate);
+       err = snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_RATE,
+                                          board_rate);
 
        if (err < 0) {
                dev_warn(chip->card->dev, "could not constrain periods\n");
index 72e89cedc52de3c1f115454e827e9d4e2c88895c..17ae92613de4bc7502f33ff64d4dc076177ef992 100644 (file)
@@ -1929,15 +1929,32 @@ snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
                return;
        snd_m3_outw(chip, val, CODEC_DATA);
        snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
+       /*
+        * Workaround for buggy ES1988 integrated AC'97 codec. It remains silent
+        * until the MASTER volume or mute is touched (alsactl restore does not
+        * work).
+        */
+       if (ac97->id == 0x45838308 && reg == AC97_MASTER) {
+               snd_m3_ac97_wait(chip);
+               snd_m3_outw(chip, val, CODEC_DATA);
+               snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
+       }
 }
 
 
-static void snd_m3_remote_codec_config(int io, int isremote)
+static void snd_m3_remote_codec_config(struct snd_m3 *chip, int isremote)
 {
+       int io = chip->iobase;
+       u16 tmp;
+
        isremote = isremote ? 1 : 0;
 
-       outw((inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
-            io + RING_BUS_CTRL_B);
+       tmp = inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK;
+       /* enable dock on Dell Latitude C810 */
+       if (chip->pci->subsystem_vendor == 0x1028 &&
+           chip->pci->subsystem_device == 0x00e5)
+               tmp |= M3I_DOCK_ENABLE;
+       outw(tmp | isremote, io + RING_BUS_CTRL_B);
        outw((inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
             io + SDO_OUT_DEST_CTRL);
        outw((inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
@@ -1989,7 +2006,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
                if (!chip->irda_workaround)
                        dir |= 0x10; /* assuming pci bus master? */
 
-               snd_m3_remote_codec_config(io, 0);
+               snd_m3_remote_codec_config(chip, 0);
 
                outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
                udelay(20);
index 23d7f5d30c4106e107436999673358e0fb65ff8b..cd94ac548ba383a99ee10886c94343877f760211 100644 (file)
@@ -831,9 +831,9 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = {
 static void snd_rme32_set_buffer_constraint(struct rme32 *rme32, struct snd_pcm_runtime *runtime)
 {
        if (! rme32->fullduplex_mode) {
-               snd_pcm_hw_constraint_minmax(runtime,
+               snd_pcm_hw_constraint_single(runtime,
                                             SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-                                            RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
+                                            RME32_BUFFER_SIZE);
                snd_pcm_hw_constraint_list(runtime, 0,
                                           SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                           &hw_constraints_period_bytes);
index 2306ccf7281e29c9e428b4349c34ade9d12e2296..714df906249eab42c54816fed4630cc4890d7603 100644 (file)
@@ -1152,13 +1152,13 @@ rme96_set_buffer_size_constraint(struct rme96 *rme96,
 {
        unsigned int size;
 
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-                                    RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                    RME96_BUFFER_SIZE);
        if ((size = rme96->playback_periodsize) != 0 ||
            (size = rme96->capture_periodsize) != 0)
-               snd_pcm_hw_constraint_minmax(runtime,
+               snd_pcm_hw_constraint_single(runtime,
                                             SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-                                            size, size);
+                                            size);
        else
                snd_pcm_hw_constraint_list(runtime, 0,
                                           SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
index 9bba275b4c9b08ba3dd4ff763afd6b17669af48d..2875b4f6d8c9e6a792638547d4b6850fa620a857 100644 (file)
@@ -5112,6 +5112,7 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
                dev_err(hdsp->card->dev,
                        "too short firmware size %d (expected %d)\n",
                           (int)fw->size, HDSP_FIRMWARE_SIZE);
+               release_firmware(fw);
                return -EINVAL;
        }
 
index cb666c73712d15276b411cdce11c7994380d4ffb..8bc8016c173d6a6005e33222df1381272bb7819e 100644 (file)
@@ -6080,18 +6080,17 @@ static int snd_hdspm_open(struct snd_pcm_substream *substream)
                                             SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
                                             32, 4096);
                /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */
-               snd_pcm_hw_constraint_minmax(runtime,
+               snd_pcm_hw_constraint_single(runtime,
                                             SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-                                            16384, 16384);
+                                            16384);
                break;
 
        default:
                snd_pcm_hw_constraint_minmax(runtime,
                                             SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
                                             64, 8192);
-               snd_pcm_hw_constraint_minmax(runtime,
-                                            SNDRV_PCM_HW_PARAM_PERIODS,
-                                            2, 2);
+               snd_pcm_hw_constraint_single(runtime,
+                                            SNDRV_PCM_HW_PARAM_PERIODS, 2);
                break;
        }
 
index 225bfda414e98d91da49140451d8bb09e16c9f12..7ff7d88e46ddd60796ada2b64c67bd6e3816ce6f 100644 (file)
@@ -9,7 +9,6 @@ menuconfig SND_SOC
        select SND_JACK if INPUT=y || INPUT=SND
        select REGMAP_I2C if I2C
        select REGMAP_SPI if SPI_MASTER
-       select SND_COMPRESS_OFFLOAD
        ---help---
 
          If you want ASoC support, you should say Y here and also to the
@@ -30,6 +29,10 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
        bool
        select SND_DMAENGINE_PCM
 
+config SND_SOC_COMPRESS
+       bool
+       select SND_COMPRESS_OFFLOAD
+
 config SND_SOC_TOPOLOGY
        bool
 
@@ -58,6 +61,7 @@ source "sound/soc/sh/Kconfig"
 source "sound/soc/sirf/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/sti/Kconfig"
+source "sound/soc/sunxi/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
index 134aca150a50bb62ef6d9d13ddc5636b7adde463..8eb06db32fa0dcd53bf2ed7ee3bd94fb92df7adb 100644 (file)
@@ -1,5 +1,6 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
+snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o
+snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o
 
 ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
 snd-soc-core-objs += soc-topology.o
@@ -40,6 +41,7 @@ obj-$(CONFIG_SND_SOC) += sh/
 obj-$(CONFIG_SND_SOC)  += sirf/
 obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += sti/
+obj-$(CONFIG_SND_SOC)  += sunxi/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
index 1489cd461aeca365cf746a09bf506668c75c1ec5..2d30464b81cef315b2faf29f6dc21352b38c60d2 100644 (file)
@@ -59,4 +59,13 @@ config SND_AT91_SOC_SAM9X5_WM8731
        help
          Say Y if you want to add support for audio SoC on an
          at91sam9x5 based board that is using WM8731 codec.
+
+config SND_ATMEL_SOC_CLASSD
+       tristate "Atmel ASoC driver for boards using CLASSD"
+       depends on ARCH_AT91 || COMPILE_TEST
+       select SND_ATMEL_SOC_DMA
+       select REGMAP_MMIO
+       help
+         Say Y if you want to add support for Atmel ASoC driver for boards using
+         CLASSD.
 endif
index b327e5cc8de352b84a8bffc5260e4d6e6ea5f2df..f6f7db4282164a7b15ffcc52535ca64c9296e045 100644 (file)
@@ -11,7 +11,9 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
 snd-atmel-soc-wm8904-objs := atmel_wm8904.o
 snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
+snd-atmel-soc-classd-objs := atmel-classd.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
+obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
new file mode 100644 (file)
index 0000000..8276675
--- /dev/null
@@ -0,0 +1,679 @@
+/* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Songjun Wu <songjun.wu@atmel.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 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "atmel-classd.h"
+
+struct atmel_classd_pdata {
+       bool non_overlap_enable;
+       int non_overlap_time;
+       int pwm_type;
+       const char *card_name;
+};
+
+struct atmel_classd {
+       dma_addr_t phy_base;
+       struct regmap *regmap;
+       struct clk *pclk;
+       struct clk *gclk;
+       struct clk *aclk;
+       int irq;
+       const struct atmel_classd_pdata *pdata;
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_classd_of_match[] = {
+       {
+               .compatible = "atmel,sama5d2-classd",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, atmel_classd_of_match);
+
+static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct atmel_classd_pdata *pdata;
+       const char *pwm_type;
+       int ret;
+
+       if (!np) {
+               dev_err(dev, "device node not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type);
+       if ((ret == 0) && (strcmp(pwm_type, "diff") == 0))
+               pdata->pwm_type = CLASSD_MR_PWMTYP_DIFF;
+       else
+               pdata->pwm_type = CLASSD_MR_PWMTYP_SINGLE;
+
+       ret = of_property_read_u32(np,
+                       "atmel,non-overlap-time", &pdata->non_overlap_time);
+       if (ret)
+               pdata->non_overlap_enable = false;
+       else
+               pdata->non_overlap_enable = true;
+
+       ret = of_property_read_string(np, "atmel,model", &pdata->card_name);
+       if (ret)
+               pdata->card_name = "CLASSD";
+
+       return pdata;
+}
+#else
+static inline struct atmel_classd_pdata *
+atmel_classd_dt_init(struct device *dev)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
+#define ATMEL_CLASSD_RATES (SNDRV_PCM_RATE_8000 \
+                       | SNDRV_PCM_RATE_16000  | SNDRV_PCM_RATE_22050 \
+                       | SNDRV_PCM_RATE_32000  | SNDRV_PCM_RATE_44100 \
+                       | SNDRV_PCM_RATE_48000  | SNDRV_PCM_RATE_88200 \
+                       | SNDRV_PCM_RATE_96000)
+
+static const struct snd_pcm_hardware atmel_classd_hw = {
+       .info                   = SNDRV_PCM_INFO_MMAP
+                               | SNDRV_PCM_INFO_MMAP_VALID
+                               | SNDRV_PCM_INFO_INTERLEAVED
+                               | SNDRV_PCM_INFO_RESUME
+                               | SNDRV_PCM_INFO_PAUSE,
+       .formats                = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates                  = ATMEL_CLASSD_RATES,
+       .rate_min               = 8000,
+       .rate_max               = 96000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 256,
+       .period_bytes_max       = 32 * 1024,
+       .periods_min            = 2,
+       .periods_max            = 256,
+};
+
+#define ATMEL_CLASSD_PREALLOC_BUF_SIZE  (64 * 1024)
+
+/* cpu dai component */
+static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+
+       regmap_write(dd->regmap, CLASSD_THR, 0x0);
+
+       return clk_prepare_enable(dd->pclk);
+}
+
+static void atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+
+       clk_disable_unprepare(dd->pclk);
+}
+
+static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = {
+       .startup        = atmel_classd_cpu_dai_startup,
+       .shutdown       = atmel_classd_cpu_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver atmel_classd_cpu_dai = {
+       .playback = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = ATMEL_CLASSD_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = &atmel_classd_cpu_dai_ops,
+};
+
+static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = {
+       .name = "atmel-classd",
+};
+
+/* platform */
+static int
+atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct dma_slave_config *slave_config)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+
+       if (params_physical_width(params) != 16) {
+               dev_err(rtd->platform->dev,
+                       "only supports 16-bit audio data\n");
+               return -EINVAL;
+       }
+
+       slave_config->direction         = DMA_MEM_TO_DEV;
+       slave_config->dst_addr          = dd->phy_base + CLASSD_THR;
+       slave_config->dst_addr_width    = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       slave_config->dst_maxburst      = 1;
+       slave_config->src_maxburst      = 1;
+       slave_config->device_fc         = false;
+
+       return 0;
+}
+
+static const struct snd_dmaengine_pcm_config
+atmel_classd_dmaengine_pcm_config = {
+       .prepare_slave_config   = atmel_classd_platform_configure_dma,
+       .pcm_hardware           = &atmel_classd_hw,
+       .prealloc_buffer_size   = ATMEL_CLASSD_PREALLOC_BUF_SIZE,
+};
+
+/* codec */
+static const char * const mono_mode_text[] = {
+       "mix", "sat", "left", "right"
+};
+
+static SOC_ENUM_SINGLE_DECL(classd_mono_mode_enum,
+                       CLASSD_INTPMR, CLASSD_INTPMR_MONO_MODE_SHIFT,
+                       mono_mode_text);
+
+static const char * const eqcfg_text[] = {
+       "Treble-12dB", "Treble-6dB",
+       "Medium-8dB", "Medium-3dB",
+       "Bass-12dB", "Bass-6dB",
+       "0 dB",
+       "Bass+6dB", "Bass+12dB",
+       "Medium+3dB", "Medium+8dB",
+       "Treble+6dB", "Treble+12dB",
+};
+
+static const unsigned int eqcfg_value[] = {
+       CLASSD_INTPMR_EQCFG_T_CUT_12, CLASSD_INTPMR_EQCFG_T_CUT_6,
+       CLASSD_INTPMR_EQCFG_M_CUT_8, CLASSD_INTPMR_EQCFG_M_CUT_3,
+       CLASSD_INTPMR_EQCFG_B_CUT_12, CLASSD_INTPMR_EQCFG_B_CUT_6,
+       CLASSD_INTPMR_EQCFG_FLAT,
+       CLASSD_INTPMR_EQCFG_B_BOOST_6, CLASSD_INTPMR_EQCFG_B_BOOST_12,
+       CLASSD_INTPMR_EQCFG_M_BOOST_3, CLASSD_INTPMR_EQCFG_M_BOOST_8,
+       CLASSD_INTPMR_EQCFG_T_BOOST_6, CLASSD_INTPMR_EQCFG_T_BOOST_12,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(classd_eqcfg_enum,
+               CLASSD_INTPMR, CLASSD_INTPMR_EQCFG_SHIFT, 0xf,
+               eqcfg_text, eqcfg_value);
+
+static const DECLARE_TLV_DB_SCALE(classd_digital_tlv, -7800, 100, 1);
+
+static const struct snd_kcontrol_new atmel_classd_snd_controls[] = {
+SOC_DOUBLE_TLV("Playback Volume", CLASSD_INTPMR,
+               CLASSD_INTPMR_ATTL_SHIFT, CLASSD_INTPMR_ATTR_SHIFT,
+               78, 1, classd_digital_tlv),
+
+SOC_SINGLE("Deemphasis Switch", CLASSD_INTPMR,
+               CLASSD_INTPMR_DEEMP_SHIFT, 1, 0),
+
+SOC_SINGLE("Mono Switch", CLASSD_INTPMR, CLASSD_INTPMR_MONO_SHIFT, 1, 0),
+
+SOC_SINGLE("Swap Switch", CLASSD_INTPMR, CLASSD_INTPMR_SWAP_SHIFT, 1, 0),
+
+SOC_ENUM("Mono Mode", classd_mono_mode_enum),
+
+SOC_ENUM("EQ", classd_eqcfg_enum),
+};
+
+static const char * const pwm_type[] = {
+       "Single ended", "Differential"
+};
+
+static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
+       const struct atmel_classd_pdata *pdata = dd->pdata;
+       u32 mask, val;
+
+       mask = CLASSD_MR_PWMTYP_MASK;
+       val = pdata->pwm_type << CLASSD_MR_PWMTYP_SHIFT;
+
+       mask |= CLASSD_MR_NON_OVERLAP_MASK;
+       if (pdata->non_overlap_enable) {
+               val |= (CLASSD_MR_NON_OVERLAP_EN
+                       << CLASSD_MR_NON_OVERLAP_SHIFT);
+
+               mask |= CLASSD_MR_NOVR_VAL_MASK;
+               switch (pdata->non_overlap_time) {
+               case 5:
+                       val |= (CLASSD_MR_NOVR_VAL_5NS
+                               << CLASSD_MR_NOVR_VAL_SHIFT);
+                       break;
+               case 10:
+                       val |= (CLASSD_MR_NOVR_VAL_10NS
+                               << CLASSD_MR_NOVR_VAL_SHIFT);
+                       break;
+               case 15:
+                       val |= (CLASSD_MR_NOVR_VAL_15NS
+                               << CLASSD_MR_NOVR_VAL_SHIFT);
+                       break;
+               case 20:
+                       val |= (CLASSD_MR_NOVR_VAL_20NS
+                               << CLASSD_MR_NOVR_VAL_SHIFT);
+                       break;
+               default:
+                       val |= (CLASSD_MR_NOVR_VAL_10NS
+                               << CLASSD_MR_NOVR_VAL_SHIFT);
+                       dev_warn(codec->dev,
+                               "non-overlapping value %d is invalid, the default value 10 is specified\n",
+                               pdata->non_overlap_time);
+                       break;
+               }
+       }
+
+       snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+
+       dev_info(codec->dev,
+               "PWM modulation type is %s, non-overlapping is %s\n",
+               pwm_type[pdata->pwm_type],
+               pdata->non_overlap_enable?"enabled":"disabled");
+
+       return 0;
+}
+
+static struct regmap *atmel_classd_codec_get_remap(struct device *dev)
+{
+       return dev_get_regmap(dev, NULL);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_classd = {
+       .probe          = atmel_classd_codec_probe,
+       .controls       = atmel_classd_snd_controls,
+       .num_controls   = ARRAY_SIZE(atmel_classd_snd_controls),
+       .get_regmap     = atmel_classd_codec_get_remap,
+};
+
+/* codec dai component */
+static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = clk_prepare_enable(dd->aclk);
+       if (ret)
+               return ret;
+
+       return clk_prepare_enable(dd->gclk);
+}
+
+static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
+       int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u32 mask, val;
+
+       mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK;
+
+       if (mute)
+               val = mask;
+       else
+               val = 0;
+
+       snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+
+       return 0;
+}
+
+#define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
+#define CLASSD_ACLK_RATE_12M288_MPY_8  (12228 * 1000 * 8)
+
+static struct {
+       int rate;
+       int sample_rate;
+       int dsp_clk;
+       unsigned long aclk_rate;
+} const sample_rates[] = {
+       { 8000,  CLASSD_INTPMR_FRAME_8K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 },
+       { 16000, CLASSD_INTPMR_FRAME_16K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 },
+       { 32000, CLASSD_INTPMR_FRAME_32K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 },
+       { 48000, CLASSD_INTPMR_FRAME_48K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 },
+       { 96000, CLASSD_INTPMR_FRAME_96K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 },
+       { 22050, CLASSD_INTPMR_FRAME_22K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 },
+       { 44100, CLASSD_INTPMR_FRAME_44K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 },
+       { 88200, CLASSD_INTPMR_FRAME_88K,
+       CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 },
+};
+
+static int
+atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int fs;
+       int i, best, best_val, cur_val, ret;
+       u32 mask, val;
+
+       fs = params_rate(params);
+
+       best = 0;
+       best_val = abs(fs - sample_rates[0].rate);
+       for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+               /* Closest match */
+               cur_val = abs(fs - sample_rates[i].rate);
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+
+       dev_dbg(codec->dev,
+               "Selected SAMPLE_RATE of %dHz, ACLK_RATE of %ldHz\n",
+               sample_rates[best].rate, sample_rates[best].aclk_rate);
+
+       clk_disable_unprepare(dd->gclk);
+       clk_disable_unprepare(dd->aclk);
+
+       ret = clk_set_rate(dd->aclk, sample_rates[best].aclk_rate);
+       if (ret)
+               return ret;
+
+       mask = CLASSD_INTPMR_DSP_CLK_FREQ_MASK | CLASSD_INTPMR_FRAME_MASK;
+       val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT)
+       | (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT);
+
+       snd_soc_update_bits(codec, CLASSD_INTPMR, mask, val);
+
+       ret = clk_prepare_enable(dd->aclk);
+       if (ret)
+               return ret;
+
+       return clk_prepare_enable(dd->gclk);
+}
+
+static void
+atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
+
+       clk_disable_unprepare(dd->gclk);
+       clk_disable_unprepare(dd->aclk);
+}
+
+static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
+                                       struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       snd_soc_update_bits(codec, CLASSD_MR,
+                               CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK,
+                               (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
+                               |(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT));
+
+       return 0;
+}
+
+static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
+                                       int cmd, struct snd_soc_dai *codec_dai)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u32 mask, val;
+
+       mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               val = mask;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               val = (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
+                       | (CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops atmel_classd_codec_dai_ops = {
+       .digital_mute   = atmel_classd_codec_dai_digital_mute,
+       .startup        = atmel_classd_codec_dai_startup,
+       .shutdown       = atmel_classd_codec_dai_shutdown,
+       .hw_params      = atmel_classd_codec_dai_hw_params,
+       .prepare        = atmel_classd_codec_dai_prepare,
+       .trigger        = atmel_classd_codec_dai_trigger,
+};
+
+#define ATMEL_CLASSD_CODEC_DAI_NAME  "atmel-classd-hifi"
+
+static struct snd_soc_dai_driver atmel_classd_codec_dai = {
+       .name = ATMEL_CLASSD_CODEC_DAI_NAME,
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = ATMEL_CLASSD_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &atmel_classd_codec_dai_ops,
+};
+
+/* ASoC sound card */
+static int atmel_classd_asoc_card_init(struct device *dev,
+                                       struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *dai_link;
+       struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
+
+       dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL);
+       if (!dai_link)
+               return -ENOMEM;
+
+       dai_link->name                  = "CLASSD";
+       dai_link->stream_name           = "CLASSD PCM";
+       dai_link->codec_dai_name        = ATMEL_CLASSD_CODEC_DAI_NAME;
+       dai_link->cpu_dai_name          = dev_name(dev);
+       dai_link->codec_name            = dev_name(dev);
+       dai_link->platform_name         = dev_name(dev);
+
+       card->dai_link  = dai_link;
+       card->num_links = 1;
+       card->name      = dd->pdata->card_name;
+       card->dev       = dev;
+
+       return 0;
+};
+
+/* regmap configuration */
+static const struct reg_default atmel_classd_reg_defaults[] = {
+       { CLASSD_INTPMR,   0x00301212 },
+};
+
+#define ATMEL_CLASSD_REG_MAX    0xE4
+static const struct regmap_config atmel_classd_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = ATMEL_CLASSD_REG_MAX,
+
+       .cache_type             = REGCACHE_FLAT,
+       .reg_defaults           = atmel_classd_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(atmel_classd_reg_defaults),
+};
+
+static int atmel_classd_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct atmel_classd *dd;
+       struct resource *res;
+       void __iomem *io_base;
+       const struct atmel_classd_pdata *pdata;
+       struct snd_soc_card *card;
+       int ret;
+
+       pdata = dev_get_platdata(dev);
+       if (!pdata) {
+               pdata = atmel_classd_dt_init(dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
+       }
+
+       dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
+       if (!dd)
+               return -ENOMEM;
+
+       dd->pdata = pdata;
+
+       dd->irq = platform_get_irq(pdev, 0);
+       if (dd->irq < 0) {
+               ret = dd->irq;
+               dev_err(dev, "failed to could not get irq: %d\n", ret);
+               return ret;
+       }
+
+       dd->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(dd->pclk)) {
+               ret = PTR_ERR(dd->pclk);
+               dev_err(dev, "failed to get peripheral clock: %d\n", ret);
+               return ret;
+       }
+
+       dd->gclk = devm_clk_get(dev, "gclk");
+       if (IS_ERR(dd->gclk)) {
+               ret = PTR_ERR(dd->gclk);
+               dev_err(dev, "failed to get GCK clock: %d\n", ret);
+               return ret;
+       }
+
+       dd->aclk = devm_clk_get(dev, "aclk");
+       if (IS_ERR(dd->aclk)) {
+               ret = PTR_ERR(dd->aclk);
+               dev_err(dev, "failed to get audio clock: %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no memory resource\n");
+               return -ENXIO;
+       }
+
+       io_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(io_base)) {
+               ret =  PTR_ERR(io_base);
+               dev_err(dev, "failed to remap register memory: %d\n", ret);
+               return ret;
+       }
+
+       dd->phy_base = res->start;
+
+       dd->regmap = devm_regmap_init_mmio(dev, io_base,
+                                       &atmel_classd_regmap_config);
+       if (IS_ERR(dd->regmap)) {
+               ret = PTR_ERR(dd->regmap);
+               dev_err(dev, "failed to init register map: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_snd_soc_register_component(dev,
+                                       &atmel_classd_cpu_dai_component,
+                                       &atmel_classd_cpu_dai, 1);
+       if (ret) {
+               dev_err(dev, "could not register CPU DAI: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_snd_dmaengine_pcm_register(dev,
+                                       &atmel_classd_dmaengine_pcm_config,
+                                       0);
+       if (ret) {
+               dev_err(dev, "could not register platform: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_codec(dev, &soc_codec_dev_classd,
+                                       &atmel_classd_codec_dai, 1);
+       if (ret) {
+               dev_err(dev, "could not register codec: %d\n", ret);
+               return ret;
+       }
+
+       /* register sound card */
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       snd_soc_card_set_drvdata(card, dd);
+       platform_set_drvdata(pdev, card);
+
+       ret = atmel_classd_asoc_card_init(dev, card);
+       if (ret) {
+               dev_err(dev, "failed to init sound card\n");
+               return ret;
+       }
+
+       ret = devm_snd_soc_register_card(dev, card);
+       if (ret) {
+               dev_err(dev, "failed to register sound card: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int atmel_classd_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver atmel_classd_driver = {
+       .driver = {
+               .name           = "atmel-classd",
+               .of_match_table = of_match_ptr(atmel_classd_of_match),
+               .pm             = &snd_soc_pm_ops,
+       },
+       .probe  = atmel_classd_probe,
+       .remove = atmel_classd_remove,
+};
+module_platform_driver(atmel_classd_driver);
+
+MODULE_DESCRIPTION("Atmel ClassD driver under ALSA SoC architecture");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel-classd.h b/sound/soc/atmel/atmel-classd.h
new file mode 100644 (file)
index 0000000..73f8fdd
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef __ATMEL_CLASSD_H_
+#define __ATMEL_CLASSD_H_
+
+#define CLASSD_CR              0x00000000
+#define CLASSD_CR_RESET                0x1
+
+#define CLASSD_MR                      0x00000004
+
+#define CLASSD_MR_LEN_DIS              0x0
+#define CLASSD_MR_LEN_EN               0x1
+#define CLASSD_MR_LEN_MASK             (0x1 << 0)
+#define CLASSD_MR_LEN_SHIFT            (0)
+
+#define CLASSD_MR_LMUTE_DIS            0x0
+#define CLASSD_MR_LMUTE_EN             0x1
+#define CLASSD_MR_LMUTE_SHIFT          (0x1)
+#define CLASSD_MR_LMUTE_MASK           (0x1 << 1)
+
+#define CLASSD_MR_REN_DIS              0x0
+#define CLASSD_MR_REN_EN               0x1
+#define CLASSD_MR_REN_MASK             (0x1 << 4)
+#define CLASSD_MR_REN_SHIFT            (4)
+
+#define CLASSD_MR_RMUTE_DIS            0x0
+#define CLASSD_MR_RMUTE_EN             0x1
+#define CLASSD_MR_RMUTE_SHIFT          (0x5)
+#define CLASSD_MR_RMUTE_MASK           (0x1 << 5)
+
+#define CLASSD_MR_PWMTYP_SINGLE                0x0
+#define CLASSD_MR_PWMTYP_DIFF          0x1
+#define CLASSD_MR_PWMTYP_MASK          (0x1 << 8)
+#define CLASSD_MR_PWMTYP_SHIFT         (8)
+
+#define CLASSD_MR_NON_OVERLAP_DIS      0x0
+#define CLASSD_MR_NON_OVERLAP_EN       0x1
+#define CLASSD_MR_NON_OVERLAP_MASK     (0x1 << 16)
+#define CLASSD_MR_NON_OVERLAP_SHIFT    (16)
+
+#define CLASSD_MR_NOVR_VAL_5NS         0x0
+#define CLASSD_MR_NOVR_VAL_10NS                0x1
+#define CLASSD_MR_NOVR_VAL_15NS                0x2
+#define CLASSD_MR_NOVR_VAL_20NS                0x3
+#define CLASSD_MR_NOVR_VAL_MASK                (0x3 << 20)
+#define CLASSD_MR_NOVR_VAL_SHIFT       (20)
+
+#define CLASSD_INTPMR                          0x00000008
+
+#define CLASSD_INTPMR_ATTL_MASK                        (0x3f << 0)
+#define CLASSD_INTPMR_ATTL_SHIFT               (0)
+#define CLASSD_INTPMR_ATTR_MASK                        (0x3f << 8)
+#define CLASSD_INTPMR_ATTR_SHIFT               (8)
+
+#define CLASSD_INTPMR_DSP_CLK_FREQ_12M288      0x0
+#define CLASSD_INTPMR_DSP_CLK_FREQ_11M2896     0x1
+#define CLASSD_INTPMR_DSP_CLK_FREQ_MASK                (0x1 << 16)
+#define CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT       (16)
+
+#define CLASSD_INTPMR_DEEMP_DIS                        0x0
+#define CLASSD_INTPMR_DEEMP_EN                 0x1
+#define CLASSD_INTPMR_DEEMP_MASK               (0x1 << 18)
+#define CLASSD_INTPMR_DEEMP_SHIFT              (18)
+
+#define CLASSD_INTPMR_SWAP_LEFT_ON_LSB         0x0
+#define CLASSD_INTPMR_SWAP_RIGHT_ON_LSB                0x1
+#define CLASSD_INTPMR_SWAP_MASK                        (0x1 << 19)
+#define CLASSD_INTPMR_SWAP_SHIFT               (19)
+
+#define CLASSD_INTPMR_FRAME_8K                 0x0
+#define CLASSD_INTPMR_FRAME_16K                        0x1
+#define CLASSD_INTPMR_FRAME_32K                        0x2
+#define CLASSD_INTPMR_FRAME_48K                        0x3
+#define CLASSD_INTPMR_FRAME_96K                        0x4
+#define CLASSD_INTPMR_FRAME_22K                        0x5
+#define CLASSD_INTPMR_FRAME_44K                        0x6
+#define CLASSD_INTPMR_FRAME_88K                        0x7
+#define CLASSD_INTPMR_FRAME_MASK               (0x7 << 20)
+#define CLASSD_INTPMR_FRAME_SHIFT              (20)
+
+#define CLASSD_INTPMR_EQCFG_FLAT               0x0
+#define CLASSD_INTPMR_EQCFG_B_BOOST_12         0x1
+#define CLASSD_INTPMR_EQCFG_B_BOOST_6          0x2
+#define CLASSD_INTPMR_EQCFG_B_CUT_12           0x3
+#define CLASSD_INTPMR_EQCFG_B_CUT_6            0x4
+#define CLASSD_INTPMR_EQCFG_M_BOOST_3          0x5
+#define CLASSD_INTPMR_EQCFG_M_BOOST_8          0x6
+#define CLASSD_INTPMR_EQCFG_M_CUT_3            0x7
+#define CLASSD_INTPMR_EQCFG_M_CUT_8            0x8
+#define CLASSD_INTPMR_EQCFG_T_BOOST_12         0x9
+#define CLASSD_INTPMR_EQCFG_T_BOOST_6          0xa
+#define CLASSD_INTPMR_EQCFG_T_CUT_12           0xb
+#define CLASSD_INTPMR_EQCFG_T_CUT_6            0xc
+#define CLASSD_INTPMR_EQCFG_SHIFT              (24)
+
+#define CLASSD_INTPMR_MONO_DIS                 0x0
+#define CLASSD_INTPMR_MONO_EN                  0x1
+#define CLASSD_INTPMR_MONO_MASK                        (0x1 << 28)
+#define CLASSD_INTPMR_MONO_SHIFT               (28)
+
+#define CLASSD_INTPMR_MONO_MODE_MIX            0x0
+#define CLASSD_INTPMR_MONO_MODE_SAT            0x1
+#define CLASSD_INTPMR_MONO_MODE_LEFT           0x2
+#define CLASSD_INTPMR_MONO_MODE_RIGHT          0x3
+#define CLASSD_INTPMR_MONO_MODE_MASK           (0x3 << 29)
+#define CLASSD_INTPMR_MONO_MODE_SHIFT          (29)
+
+#define CLASSD_INTSR   0x0000000c
+
+#define CLASSD_THR     0x00000010
+
+#define CLASSD_IER     0x00000014
+
+#define CLASSD_IDR     0x00000018
+
+#define CLASSD_IMR     0x0000001c
+
+#define CLASSD_ISR     0x00000020
+
+#define CLASSD_WPMR    0x000000e4
+
+#endif
index aa354e1c6ff7ce3df7ffd898682c3040817a6a8c..1933bcd46cca043d68db0ecc771124da37416908 100644 (file)
@@ -176,6 +176,7 @@ static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
        { .compatible = "atmel,asoc-wm8904", },
        { }
 };
+MODULE_DEVICE_TABLE(of, atmel_asoc_wm8904_dt_ids);
 #endif
 
 static struct platform_driver atmel_asoc_wm8904_driver = {
index 452f404abfd283abe56caaae06de856a47d2b1d9..e97c32798e98a066dba2eaf47883584f7eb04dad 100644 (file)
@@ -38,14 +38,7 @@ static int db1000_audio_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &db1000_ac97;
        card->dev = &pdev->dev;
-       return snd_soc_register_card(card);
-}
-
-static int db1000_audio_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-       snd_soc_unregister_card(card);
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver db1000_audio_driver = {
@@ -54,7 +47,6 @@ static struct platform_driver db1000_audio_driver = {
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = db1000_audio_probe,
-       .remove         = db1000_audio_remove,
 };
 
 module_platform_driver(db1000_audio_driver);
index 8c907ebea18960ec8e48942f5746fd2121705736..5c73061d912ad55a2cf51e75f9779bad900f9f33 100644 (file)
@@ -178,14 +178,7 @@ static int db1200_audio_probe(struct platform_device *pdev)
 
        card = db1200_cards[pid->driver_data];
        card->dev = &pdev->dev;
-       return snd_soc_register_card(card);
-}
-
-static int db1200_audio_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-       snd_soc_unregister_card(card);
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver db1200_audio_driver = {
@@ -195,7 +188,6 @@ static struct platform_driver db1200_audio_driver = {
        },
        .id_table       = db1200_pids,
        .probe          = db1200_audio_probe,
-       .remove         = db1200_audio_remove,
 };
 
 module_platform_driver(db1200_audio_driver);
index 5bf1501e5e3c4833cbebf2f5afe4b8fde1cc216f..864df2616e109ae4e2bb70793e6231abe58fd1bc 100644 (file)
@@ -87,27 +87,18 @@ static int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "Failed to register card\n");
        return ret;
 }
 
-static int bf5xx_ad1836_driver_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static struct platform_driver bf5xx_ad1836_driver = {
        .driver = {
                .name = "bfin-snd-ad1836",
                .pm = &snd_soc_pm_ops,
        },
        .probe = bf5xx_ad1836_driver_probe,
-       .remove = bf5xx_ad1836_driver_remove,
 };
 module_platform_driver(bf5xx_ad1836_driver);
 
index 523baf5820d737113e3ba17536a788026cf62137..72ac789884262bbdc41e63adfcabe1dee3911814 100644 (file)
@@ -154,16 +154,7 @@ static int bfin_eval_adau1373_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       return snd_soc_register_card(&bfin_eval_adau1373);
-}
-
-static int bfin_eval_adau1373_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1373);
 }
 
 static struct platform_driver bfin_eval_adau1373_driver = {
@@ -172,7 +163,6 @@ static struct platform_driver bfin_eval_adau1373_driver = {
                .pm = &snd_soc_pm_ops,
        },
        .probe = bfin_eval_adau1373_probe,
-       .remove = bfin_eval_adau1373_remove,
 };
 
 module_platform_driver(bfin_eval_adau1373_driver);
index f9e926dfd4ef735af9e84f9e35363a1670e61421..5c67f72cf9a95e521eb070e5e9b1c9a0835873c8 100644 (file)
@@ -94,16 +94,7 @@ static int bfin_eval_adau1701_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       return snd_soc_register_card(&bfin_eval_adau1701);
-}
-
-static int bfin_eval_adau1701_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1701);
 }
 
 static struct platform_driver bfin_eval_adau1701_driver = {
@@ -112,7 +103,6 @@ static struct platform_driver bfin_eval_adau1701_driver = {
                .pm = &snd_soc_pm_ops,
        },
        .probe = bfin_eval_adau1701_probe,
-       .remove = bfin_eval_adau1701_remove,
 };
 
 module_platform_driver(bfin_eval_adau1701_driver);
index 27eee66afdb26536aeb41d50e1b29e542bf6b0c5..1037477d10b2f962cf6d7ea13844d01539bdeafb 100644 (file)
@@ -119,16 +119,7 @@ static int bfin_eval_adav80x_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       return snd_soc_register_card(&bfin_eval_adav80x);
-}
-
-static int bfin_eval_adav80x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adav80x);
 }
 
 static const struct platform_device_id bfin_eval_adav80x_ids[] = {
@@ -144,7 +135,6 @@ static struct platform_driver bfin_eval_adav80x_driver = {
                .pm = &snd_soc_pm_ops,
        },
        .probe = bfin_eval_adav80x_probe,
-       .remove = bfin_eval_adav80x_remove,
        .id_table = bfin_eval_adav80x_ids,
 };
 
index 0c9733ecd17f29a040ec3f2a4c7dfab8c59007e7..cfdafc4c11ea9a64c465eef6d9ac4ed3520c159a 100644 (file)
@@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
        select SND_SOC_AK4554
+       select SND_SOC_AK4613 if I2C
        select SND_SOC_AK4641 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
@@ -57,6 +58,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CX20442 if TTY
        select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
        select SND_SOC_DA7213 if I2C
+       select SND_SOC_DA7219 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
        select SND_SOC_DMIC
@@ -79,7 +81,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_MC13783 if MFD_MC13XXX
        select SND_SOC_ML26124 if I2C
-       select SND_SOC_HDMI_CODEC
+       select SND_SOC_NAU8825 if I2C
        select SND_SOC_PCM1681 if I2C
        select SND_SOC_PCM1792A if SPI_MASTER
        select SND_SOC_PCM3008
@@ -171,6 +173,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8996 if I2C
        select SND_SOC_WM8997 if MFD_WM8997
+       select SND_SOC_WM8998 if MFD_WM8998
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9090 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -195,9 +198,11 @@ config SND_SOC_ARIZONA
        default y if SND_SOC_WM5102=y
        default y if SND_SOC_WM5110=y
        default y if SND_SOC_WM8997=y
+       default y if SND_SOC_WM8998=y
        default m if SND_SOC_WM5102=m
        default m if SND_SOC_WM5110=m
        default m if SND_SOC_WM8997=m
+       default m if SND_SOC_WM8998=m
 
 config SND_SOC_WM_HUBS
        tristate
@@ -319,6 +324,10 @@ config SND_SOC_AK4535
 config SND_SOC_AK4554
        tristate "AKM AK4554 CODEC"
 
+config SND_SOC_AK4613
+       tristate "AKM AK4613 CODEC"
+       depends on I2C
+
 config SND_SOC_AK4641
        tristate
 
@@ -430,6 +439,9 @@ config SND_SOC_DA7210
 config SND_SOC_DA7213
         tristate
 
+config SND_SOC_DA7219
+        tristate
+
 config SND_SOC_DA732X
         tristate
 
@@ -442,9 +454,6 @@ config SND_SOC_BT_SCO
 config SND_SOC_DMIC
        tristate
 
-config SND_SOC_HDMI_CODEC
-       tristate "HDMI stub CODEC"
-
 config SND_SOC_ES8328
        tristate "Everest Semi ES8328 CODEC"
 
@@ -865,6 +874,9 @@ config SND_SOC_WM8996
 config SND_SOC_WM8997
        tristate
 
+config SND_SOC_WM8998
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
@@ -896,6 +908,9 @@ config SND_SOC_MC13783
 config SND_SOC_ML26124
        tristate
 
+config SND_SOC_NAU8825
+       tristate
+
 config SND_SOC_TPA6130A2
        tristate "Texas Instruments TPA6130A2 headphone amplifier"
        depends on I2C
index 4a32077954aee6aee2966ced2573991d1673b02a..f632fc42f59f08d9d6c72f6aac045d9fe28176a1 100644 (file)
@@ -26,6 +26,7 @@ snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4554-objs := ak4554.o
+snd-soc-ak4613-objs := ak4613.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
@@ -49,6 +50,7 @@ snd-soc-cs4349-objs := cs4349.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
+snd-soc-da7219-objs := da7219.o da7219-aad.o
 snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-bt-sco-objs := bt-sco.o
@@ -72,7 +74,7 @@ snd-soc-max98925-objs := max98925.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
-snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-nau8825-objs := nau8825.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
@@ -176,6 +178,7 @@ snd-soc-wm8993-objs := wm8993.o
 snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm8997-objs := wm8997.o
+snd-soc-wm8998-objs := wm8998.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9090-objs := wm9090.o
 snd-soc-wm9705-objs := wm9705.o
@@ -216,6 +219,7 @@ obj-$(CONFIG_SND_SOC_ADS117X)       += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4554)   += snd-soc-ak4554.o
+obj-$(CONFIG_SND_SOC_AK4613)   += snd-soc-ak4613.o
 obj-$(CONFIG_SND_SOC_AK4641)   += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
@@ -241,6 +245,7 @@ obj-$(CONFIG_SND_SOC_CS4349)        += snd-soc-cs4349.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)   += snd-soc-da7213.o
+obj-$(CONFIG_SND_SOC_DA7219)   += snd-soc-da7219.o
 obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
@@ -264,7 +269,7 @@ obj-$(CONFIG_SND_SOC_MAX98925)      += snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
-obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
@@ -364,6 +369,7 @@ obj-$(CONFIG_SND_SOC_WM8993)        += snd-soc-wm8993.o
 obj-$(CONFIG_SND_SOC_WM8994)   += snd-soc-wm8994.o
 obj-$(CONFIG_SND_SOC_WM8995)   += snd-soc-wm8995.o
 obj-$(CONFIG_SND_SOC_WM8997)   += snd-soc-wm8997.o
+obj-$(CONFIG_SND_SOC_WM8998)   += snd-soc-wm8998.o
 obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9090)   += snd-soc-wm9090.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
index df3a1a415825bf6c0a599344611a769066e850bc..171313664bc8dac6472dcf423063882fb4ffd8f2 100644 (file)
@@ -15,8 +15,8 @@
 #include "ad193x.h"
 
 static const struct i2c_device_id ad193x_id[] = {
-       { "ad1936", 0 },
-       { "ad1937", 0 },
+       { "ad1936", AD193X },
+       { "ad1937", AD193X },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ad193x_id);
@@ -30,7 +30,9 @@ static int ad193x_i2c_probe(struct i2c_client *client,
        config.val_bits = 8;
        config.reg_bits = 8;
 
-       return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config));
+       return ad193x_probe(&client->dev,
+                           devm_regmap_init_i2c(client, &config),
+                           (enum ad193x_type)id->driver_data);
 }
 
 static int ad193x_i2c_remove(struct i2c_client *client)
index 8199a3de0024eaf84c14ce652f58e0c9af30e3ba..23c28573bdb7057356c569cb0d6054cd041611b0 100644 (file)
@@ -16,6 +16,7 @@
 
 static int ad193x_spi_probe(struct spi_device *spi)
 {
+       const struct spi_device_id *id = spi_get_device_id(spi);
        struct regmap_config config;
 
        config = ad193x_regmap_config;
@@ -24,7 +25,8 @@ static int ad193x_spi_probe(struct spi_device *spi)
        config.read_flag_mask = 0x09;
        config.write_flag_mask = 0x08;
 
-       return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+       return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config),
+                           (enum ad193x_type)id->driver_data);
 }
 
 static int ad193x_spi_remove(struct spi_device *spi)
@@ -33,12 +35,24 @@ static int ad193x_spi_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct spi_device_id ad193x_spi_id[] = {
+       { "ad193x", AD193X },
+       { "ad1933", AD1933 },
+       { "ad1934", AD1934 },
+       { "ad1938", AD193X },
+       { "ad1939", AD193X },
+       { "adau1328", AD193X },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ad193x_spi_id);
+
 static struct spi_driver ad193x_spi_driver = {
        .driver = {
                .name   = "ad193x",
        },
        .probe          = ad193x_spi_probe,
        .remove         = ad193x_spi_remove,
+       .id_table       = ad193x_spi_id,
 };
 module_spi_driver(ad193x_spi_driver);
 
index 17c9535956609c0df1a04f631da8f79a25a1e044..3a3f3f2343d75e7ee8b9b29abd3ee6887c1437f4 100644 (file)
@@ -23,6 +23,7 @@
 /* codec private data */
 struct ad193x_priv {
        struct regmap *regmap;
+       enum ad193x_type type;
        int sysclk;
 };
 
@@ -47,12 +48,6 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,
                        AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),
 
-       /* ADC switch control */
-       SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
-               AD193X_ADCR1_MUTE, 1, 1),
-       SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
-               AD193X_ADCR2_MUTE, 1, 1),
-
        /* DAC switch control */
        SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,
                AD193X_DACR1_MUTE, 1, 1),
@@ -63,26 +58,37 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
        SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,
                AD193X_DACR4_MUTE, 1, 1),
 
+       /* DAC de-emphasis */
+       SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
+};
+
+static const struct snd_kcontrol_new ad193x_adc_snd_controls[] = {
+       /* ADC switch control */
+       SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
+               AD193X_ADCR1_MUTE, 1, 1),
+       SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
+               AD193X_ADCR2_MUTE, 1, 1),
+
        /* ADC high-pass filter */
        SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,
                        AD193X_ADC_HIGHPASS_FILTER, 1, 0),
-
-       /* DAC de-emphasis */
-       SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
 };
 
 static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
-       SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
        SND_SOC_DAPM_VMID("VMID"),
        SND_SOC_DAPM_OUTPUT("DAC1OUT"),
        SND_SOC_DAPM_OUTPUT("DAC2OUT"),
        SND_SOC_DAPM_OUTPUT("DAC3OUT"),
        SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+};
+
+static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = {
+       SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
        SND_SOC_DAPM_INPUT("ADC1IN"),
        SND_SOC_DAPM_INPUT("ADC2IN"),
 };
@@ -91,18 +97,33 @@ static const struct snd_soc_dapm_route audio_paths[] = {
        { "DAC", NULL, "SYSCLK" },
        { "DAC Output", NULL, "DAC" },
        { "DAC Output", NULL, "VMID" },
-       { "ADC", NULL, "SYSCLK" },
-       { "DAC", NULL, "ADC_PWR" },
-       { "ADC", NULL, "ADC_PWR" },
        { "DAC1OUT", NULL, "DAC Output" },
        { "DAC2OUT", NULL, "DAC Output" },
        { "DAC3OUT", NULL, "DAC Output" },
        { "DAC4OUT", NULL, "DAC Output" },
+       { "SYSCLK", NULL, "PLL_PWR" },
+};
+
+static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = {
+       { "ADC", NULL, "SYSCLK" },
+       { "ADC", NULL, "ADC_PWR" },
        { "ADC", NULL, "ADC1IN" },
        { "ADC", NULL, "ADC2IN" },
-       { "SYSCLK", NULL, "PLL_PWR" },
 };
 
+static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x)
+{
+       switch (ad193x->type) {
+       case AD1933:
+       case AD1934:
+               return false;
+       default:
+               break;
+       }
+
+       return true;
+}
+
 /*
  * DAI ops entries
  */
@@ -147,8 +168,10 @@ static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
        regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
                AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);
-       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
-               AD193X_ADC_CHAN_MASK, channels << AD193X_ADC_CHAN_SHFT);
+       if (ad193x_has_adc(ad193x))
+               regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+                                  AD193X_ADC_CHAN_MASK,
+                                  channels << AD193X_ADC_CHAN_SHFT);
 
        return 0;
 }
@@ -172,7 +195,9 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                adc_serfmt |= AD193X_ADC_SERFMT_AUX;
                break;
        default:
-               return -EINVAL;
+               if (ad193x_has_adc(ad193x))
+                       return -EINVAL;
+               break;
        }
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -217,10 +242,12 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
-               AD193X_ADC_SERFMT_MASK, adc_serfmt);
-       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
-               AD193X_ADC_FMT_MASK, adc_fmt);
+       if (ad193x_has_adc(ad193x)) {
+               regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
+                                  AD193X_ADC_SERFMT_MASK, adc_serfmt);
+               regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+                                  AD193X_ADC_FMT_MASK, adc_fmt);
+       }
        regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
                AD193X_DAC_FMT_MASK, dac_fmt);
 
@@ -287,8 +314,9 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
                            AD193X_DAC_WORD_LEN_MASK,
                            word_len << AD193X_DAC_WORD_LEN_SHFT);
 
-       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
-                           AD193X_ADC_WORD_LEN_MASK, word_len);
+       if (ad193x_has_adc(ad193x))
+               regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
+                                  AD193X_ADC_WORD_LEN_MASK, word_len);
 
        return 0;
 }
@@ -326,6 +354,8 @@ static struct snd_soc_dai_driver ad193x_dai = {
 static int ad193x_codec_probe(struct snd_soc_codec *codec)
 {
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       int num, ret;
 
        /* default setting for ad193x */
 
@@ -335,14 +365,46 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
        regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
        /* dac in tdm mode */
        regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
-       /* high-pass filter enable */
-       regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
-       /* sata delay=1, adc aux mode */
-       regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
+
+       /* adc only */
+       if (ad193x_has_adc(ad193x)) {
+               /* high-pass filter enable */
+               regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
+               /* sata delay=1, adc aux mode */
+               regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
+       }
+
        /* pll input: mclki/xi */
        regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
        regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
 
+       /* adc only */
+       if (ad193x_has_adc(ad193x)) {
+               /* add adc controls */
+               num = ARRAY_SIZE(ad193x_adc_snd_controls);
+               ret = snd_soc_add_codec_controls(codec,
+                                                ad193x_adc_snd_controls,
+                                                num);
+               if (ret)
+                       return ret;
+
+               /* add adc widgets */
+               num = ARRAY_SIZE(ad193x_adc_widgets);
+               ret = snd_soc_dapm_new_controls(dapm,
+                                               ad193x_adc_widgets,
+                                               num);
+               if (ret)
+                       return ret;
+
+               /* add adc routes */
+               num = ARRAY_SIZE(ad193x_adc_audio_paths);
+               ret = snd_soc_dapm_add_routes(dapm,
+                                             ad193x_adc_audio_paths,
+                                             num);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -356,18 +418,13 @@ static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
        .num_dapm_routes = ARRAY_SIZE(audio_paths),
 };
 
-static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
-{
-       return false;
-}
-
 const struct regmap_config ad193x_regmap_config = {
        .max_register = AD193X_NUM_REGS - 1,
-       .volatile_reg = adau193x_reg_volatile,
 };
 EXPORT_SYMBOL_GPL(ad193x_regmap_config);
 
-int ad193x_probe(struct device *dev, struct regmap *regmap)
+int ad193x_probe(struct device *dev, struct regmap *regmap,
+                enum ad193x_type type)
 {
        struct ad193x_priv *ad193x;
 
@@ -379,6 +436,7 @@ int ad193x_probe(struct device *dev, struct regmap *regmap)
                return -ENOMEM;
 
        ad193x->regmap = regmap;
+       ad193x->type = type;
 
        dev_set_drvdata(dev, ad193x);
 
index ab9a998f15beba416338b9571e64601608fe5fc7..8b1e65f928d2ad92cabb6f6773af487c1b94a1bc 100644 (file)
 
 struct device;
 
+enum ad193x_type {
+       AD193X,
+       AD1933,
+       AD1934,
+};
+
 extern const struct regmap_config ad193x_regmap_config;
-int ad193x_probe(struct device *dev, struct regmap *regmap);
+int ad193x_probe(struct device *dev, struct regmap *regmap,
+                enum ad193x_type type);
 
 #define AD193X_PLL_CLK_CTRL0    0x00
 #define AD193X_PLL_POWERDOWN           0x01
index 198c924551b78e268b8480a38d481703fe53d3a9..acff8d62059cf49de24585aeac9c2143412c0175 100644 (file)
@@ -728,8 +728,8 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
        if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
                return 0;
 
-       return snd_pcm_hw_constraint_minmax(substream->runtime,
-                       SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate);
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, adav80x->rate);
 }
 
 static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
new file mode 100644 (file)
index 0000000..07a2664
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on ak4642.c by Kuninori Morimoto
+ * Based on wm8731.c by Richard Purdie
+ * Based on ak4535.c by Richard Purdie
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define PW_MGMT1       0x00 /* Power Management 1 */
+#define PW_MGMT2       0x01 /* Power Management 2 */
+#define PW_MGMT3       0x02 /* Power Management 3 */
+#define CTRL1          0x03 /* Control 1 */
+#define CTRL2          0x04 /* Control 2 */
+#define DEMP1          0x05 /* De-emphasis1 */
+#define DEMP2          0x06 /* De-emphasis2 */
+#define OFD            0x07 /* Overflow Detect */
+#define ZRD            0x08 /* Zero Detect */
+#define ICTRL          0x09 /* Input Control */
+#define OCTRL          0x0a /* Output Control */
+#define LOUT1          0x0b /* LOUT1 Volume Control */
+#define ROUT1          0x0c /* ROUT1 Volume Control */
+#define LOUT2          0x0d /* LOUT2 Volume Control */
+#define ROUT2          0x0e /* ROUT2 Volume Control */
+#define LOUT3          0x0f /* LOUT3 Volume Control */
+#define ROUT3          0x10 /* ROUT3 Volume Control */
+#define LOUT4          0x11 /* LOUT4 Volume Control */
+#define ROUT4          0x12 /* ROUT4 Volume Control */
+#define LOUT5          0x13 /* LOUT5 Volume Control */
+#define ROUT5          0x14 /* ROUT5 Volume Control */
+#define LOUT6          0x15 /* LOUT6 Volume Control */
+#define ROUT6          0x16 /* ROUT6 Volume Control */
+
+/* PW_MGMT1 */
+#define RSTN           BIT(0)
+#define PMDAC          BIT(1)
+#define PMADC          BIT(2)
+#define PMVR           BIT(3)
+
+/* PW_MGMT2 */
+#define PMAD_ALL       0x7
+
+/* PW_MGMT3 */
+#define PMDA_ALL       0x3f
+
+/* CTRL1 */
+#define DIF0           BIT(3)
+#define DIF1           BIT(4)
+#define DIF2           BIT(5)
+#define TDM0           BIT(6)
+#define TDM1           BIT(7)
+#define NO_FMT         (0xff)
+#define FMT_MASK       (0xf8)
+
+/* CTRL2 */
+#define DFS_NORMAL_SPEED       (0 << 2)
+#define DFS_DOUBLE_SPEED       (1 << 2)
+#define DFS_QUAD_SPEED         (2 << 2)
+
+struct ak4613_priv {
+       struct mutex lock;
+
+       unsigned int fmt;
+       u8 fmt_ctrl;
+       int cnt;
+};
+
+struct ak4613_formats {
+       unsigned int width;
+       unsigned int fmt;
+};
+
+struct ak4613_interface {
+       struct ak4613_formats capture;
+       struct ak4613_formats playback;
+};
+
+/*
+ * Playback Volume
+ *
+ * max : 0x00 : 0 dB
+ *       ( 0.5 dB step )
+ * min : 0xFE : -127.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new ak4613_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1,
+                        0, 0xFF, 1, out_tlv),
+       SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2,
+                        0, 0xFF, 1, out_tlv),
+       SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3,
+                        0, 0xFF, 1, out_tlv),
+       SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4,
+                        0, 0xFF, 1, out_tlv),
+       SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5,
+                        0, 0xFF, 1, out_tlv),
+       SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6,
+                        0, 0xFF, 1, out_tlv),
+};
+
+static const struct reg_default ak4613_reg[] = {
+       { 0x0,  0x0f }, { 0x1,  0x07 }, { 0x2,  0x3f }, { 0x3,  0x20 },
+       { 0x4,  0x20 }, { 0x5,  0x55 }, { 0x6,  0x05 }, { 0x7,  0x07 },
+       { 0x8,  0x0f }, { 0x9,  0x07 }, { 0xa,  0x3f }, { 0xb,  0x00 },
+       { 0xc,  0x00 }, { 0xd,  0x00 }, { 0xe,  0x00 }, { 0xf,  0x00 },
+       { 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
+       { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
+};
+
+#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
+static const struct ak4613_interface ak4613_iface[] = {
+       /* capture */                           /* playback */
+       [0] = { AUDIO_IFACE(24, LEFT_J),        AUDIO_IFACE(16, RIGHT_J) },
+       [1] = { AUDIO_IFACE(24, LEFT_J),        AUDIO_IFACE(20, RIGHT_J) },
+       [2] = { AUDIO_IFACE(24, LEFT_J),        AUDIO_IFACE(24, RIGHT_J) },
+       [3] = { AUDIO_IFACE(24, LEFT_J),        AUDIO_IFACE(24, LEFT_J) },
+       [4] = { AUDIO_IFACE(24, I2S),           AUDIO_IFACE(24, I2S) },
+};
+
+static const struct regmap_config ak4613_regmap_cfg = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = 0x16,
+       .reg_defaults           = ak4613_reg,
+       .num_reg_defaults       = ARRAY_SIZE(ak4613_reg),
+};
+
+static const struct of_device_id ak4613_of_match[] = {
+       { .compatible = "asahi-kasei,ak4613",   .data = &ak4613_regmap_cfg },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ak4613_of_match);
+
+static const struct i2c_device_id ak4613_i2c_id[] = {
+       { "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
+
+static const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("LOUT1"),
+       SND_SOC_DAPM_OUTPUT("LOUT2"),
+       SND_SOC_DAPM_OUTPUT("LOUT3"),
+       SND_SOC_DAPM_OUTPUT("LOUT4"),
+       SND_SOC_DAPM_OUTPUT("LOUT5"),
+       SND_SOC_DAPM_OUTPUT("LOUT6"),
+
+       SND_SOC_DAPM_OUTPUT("ROUT1"),
+       SND_SOC_DAPM_OUTPUT("ROUT2"),
+       SND_SOC_DAPM_OUTPUT("ROUT3"),
+       SND_SOC_DAPM_OUTPUT("ROUT4"),
+       SND_SOC_DAPM_OUTPUT("ROUT5"),
+       SND_SOC_DAPM_OUTPUT("ROUT6"),
+
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("LIN1"),
+       SND_SOC_DAPM_INPUT("LIN2"),
+
+       SND_SOC_DAPM_INPUT("RIN1"),
+       SND_SOC_DAPM_INPUT("RIN2"),
+
+       /* DAC */
+       SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
+       SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
+       SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
+       SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
+       SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
+       SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
+
+       /* ADC */
+       SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
+};
+
+static const struct snd_soc_dapm_route ak4613_intercon[] = {
+       {"LOUT1", NULL, "DAC1"},
+       {"LOUT2", NULL, "DAC2"},
+       {"LOUT3", NULL, "DAC3"},
+       {"LOUT4", NULL, "DAC4"},
+       {"LOUT5", NULL, "DAC5"},
+       {"LOUT6", NULL, "DAC6"},
+
+       {"ROUT1", NULL, "DAC1"},
+       {"ROUT2", NULL, "DAC2"},
+       {"ROUT3", NULL, "DAC3"},
+       {"ROUT4", NULL, "DAC4"},
+       {"ROUT5", NULL, "DAC5"},
+       {"ROUT6", NULL, "DAC6"},
+
+       {"DAC1", NULL, "Playback"},
+       {"DAC2", NULL, "Playback"},
+       {"DAC3", NULL, "Playback"},
+       {"DAC4", NULL, "Playback"},
+       {"DAC5", NULL, "Playback"},
+       {"DAC6", NULL, "Playback"},
+
+       {"Capture", NULL, "ADC1"},
+       {"Capture", NULL, "ADC2"},
+
+       {"ADC1", NULL, "LIN1"},
+       {"ADC2", NULL, "LIN2"},
+
+       {"ADC1", NULL, "RIN1"},
+       {"ADC2", NULL, "RIN2"},
+};
+
+static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = codec->dev;
+
+       mutex_lock(&priv->lock);
+       priv->cnt--;
+       if (priv->cnt < 0) {
+               dev_err(dev, "unexpected counter error\n");
+               priv->cnt = 0;
+       }
+       if (!priv->cnt)
+               priv->fmt_ctrl = NO_FMT;
+       mutex_unlock(&priv->lock);
+}
+
+static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
+
+       switch (fmt) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_I2S:
+               priv->fmt = fmt;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+       const struct ak4613_formats *fmts;
+       struct device *dev = codec->dev;
+       unsigned int width = params_width(params);
+       unsigned int fmt = priv->fmt;
+       unsigned int rate;
+       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int i, ret;
+       u8 fmt_ctrl, ctrl2;
+
+       rate = params_rate(params);
+       switch (rate) {
+       case 32000:
+       case 44100:
+       case 48000:
+               ctrl2 = DFS_NORMAL_SPEED;
+               break;
+       case 88200:
+       case 96000:
+               ctrl2 = DFS_DOUBLE_SPEED;
+               break;
+       case 176400:
+       case 192000:
+               ctrl2 = DFS_QUAD_SPEED;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * FIXME
+        *
+        * It doesn't support TDM at this point
+        */
+       fmt_ctrl = NO_FMT;
+       for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
+               fmts = (is_play) ?      &ak4613_iface[i].playback :
+                                       &ak4613_iface[i].capture;
+
+               if (fmts->fmt != fmt)
+                       continue;
+
+               if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+                       if (fmts->width != width)
+                               continue;
+               } else {
+                       if (fmts->width < width)
+                               continue;
+               }
+
+               fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
+               break;
+       }
+
+       ret = -EINVAL;
+       if (fmt_ctrl == NO_FMT)
+               goto hw_params_end;
+
+       mutex_lock(&priv->lock);
+       if ((priv->fmt_ctrl == NO_FMT) ||
+           (priv->fmt_ctrl == fmt_ctrl)) {
+               priv->fmt_ctrl = fmt_ctrl;
+               priv->cnt++;
+               ret = 0;
+       }
+       mutex_unlock(&priv->lock);
+
+       if (ret < 0)
+               goto hw_params_end;
+
+       snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
+       snd_soc_write(codec, CTRL2, ctrl2);
+
+hw_params_end:
+       if (ret < 0)
+               dev_warn(dev, "unsupported data width/format combination\n");
+
+       return ret;
+}
+
+static int ak4613_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u8 mgmt1 = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               mgmt1 |= RSTN;
+               /* fall through */
+       case SND_SOC_BIAS_PREPARE:
+               mgmt1 |= PMADC | PMDAC;
+               /* fall through */
+       case SND_SOC_BIAS_STANDBY:
+               mgmt1 |= PMVR;
+               /* fall through */
+       case SND_SOC_BIAS_OFF:
+       default:
+               break;
+       }
+
+       snd_soc_write(codec, PW_MGMT1, mgmt1);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ak4613_dai_ops = {
+       .shutdown       = ak4613_dai_shutdown,
+       .set_fmt        = ak4613_dai_set_fmt,
+       .hw_params      = ak4613_dai_hw_params,
+};
+
+#define AK4613_PCM_RATE                (SNDRV_PCM_RATE_32000  |\
+                                SNDRV_PCM_RATE_44100  |\
+                                SNDRV_PCM_RATE_48000  |\
+                                SNDRV_PCM_RATE_64000  |\
+                                SNDRV_PCM_RATE_88200  |\
+                                SNDRV_PCM_RATE_96000  |\
+                                SNDRV_PCM_RATE_176400 |\
+                                SNDRV_PCM_RATE_192000)
+#define AK4613_PCM_FMTBIT      (SNDRV_PCM_FMTBIT_S16_LE |\
+                                SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4613_dai = {
+       .name = "ak4613-hifi",
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = AK4613_PCM_RATE,
+               .formats        = AK4613_PCM_FMTBIT,
+       },
+       .capture = {
+               .stream_name    = "Capture",
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = AK4613_PCM_RATE,
+               .formats        = AK4613_PCM_FMTBIT,
+       },
+       .ops = &ak4613_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static int ak4613_resume(struct snd_soc_codec *codec)
+{
+       struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+
+       regcache_mark_dirty(regmap);
+       return regcache_sync(regmap);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+       .resume                 = ak4613_resume,
+       .set_bias_level         = ak4613_set_bias_level,
+       .controls               = ak4613_snd_controls,
+       .num_controls           = ARRAY_SIZE(ak4613_snd_controls),
+       .dapm_widgets           = ak4613_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(ak4613_dapm_widgets),
+       .dapm_routes            = ak4613_intercon,
+       .num_dapm_routes        = ARRAY_SIZE(ak4613_intercon),
+};
+
+static int ak4613_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct device *dev = &i2c->dev;
+       struct device_node *np = dev->of_node;
+       const struct regmap_config *regmap_cfg;
+       struct regmap *regmap;
+       struct ak4613_priv *priv;
+
+       regmap_cfg = NULL;
+       if (np) {
+               const struct of_device_id *of_id;
+
+               of_id = of_match_device(ak4613_of_match, dev);
+               if (of_id)
+                       regmap_cfg = of_id->data;
+       } else {
+               regmap_cfg = (const struct regmap_config *)id->driver_data;
+       }
+
+       if (!regmap_cfg)
+               return -EINVAL;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->fmt_ctrl          = NO_FMT;
+       priv->cnt               = 0;
+
+       mutex_init(&priv->lock);
+
+       i2c_set_clientdata(i2c, priv);
+
+       regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return snd_soc_register_codec(dev, &soc_codec_dev_ak4613,
+                                     &ak4613_dai, 1);
+}
+
+static int ak4613_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static struct i2c_driver ak4613_i2c_driver = {
+       .driver = {
+               .name = "ak4613-codec",
+               .owner = THIS_MODULE,
+               .of_match_table = ak4613_of_match,
+       },
+       .probe          = ak4613_i2c_probe,
+       .remove         = ak4613_i2c_remove,
+       .id_table       = ak4613_i2c_id,
+};
+
+module_i2c_driver(ak4613_i2c_driver);
+
+MODULE_DESCRIPTION("Soc AK4613 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_LICENSE("GPL v2");
index 4a90143d0e907b5034d0f4caa506c97000500f71..cda27c22812a71442dd3d927088c2118aa16dc17 100644 (file)
@@ -23,6 +23,8 @@
  * AK4648 is tested.
  */
 
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #define I2S            (3 << 0)
 
 /* MD_CTL2 */
-#define FS0            (1 << 0)
-#define FS1            (1 << 1)
-#define FS2            (1 << 2)
-#define FS3            (1 << 5)
-#define FS_MASK                (FS0 | FS1 | FS2 | FS3)
+#define FSs(val)       (((val & 0x7) << 0) | ((val & 0x8) << 2))
+#define PSs(val)       ((val & 0x3) << 6)
 
 /* MD_CTL3 */
 #define BST1           (1 << 3)
@@ -147,6 +146,7 @@ struct ak4642_drvdata {
 
 struct ak4642_priv {
        const struct ak4642_drvdata *drvdata;
+       struct clk *mcko;
 };
 
 /*
@@ -430,56 +430,56 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
+static int ak4642_set_mcko(struct snd_soc_codec *codec,
+                          u32 frequency)
+{
+       u32 fs_list[] = {
+               [0] = 8000,
+               [1] = 12000,
+               [2] = 16000,
+               [3] = 24000,
+               [4] = 7350,
+               [5] = 11025,
+               [6] = 14700,
+               [7] = 22050,
+               [10] = 32000,
+               [11] = 48000,
+               [14] = 29400,
+               [15] = 44100,
+       };
+       u32 ps_list[] = {
+               [0] = 256,
+               [1] = 128,
+               [2] = 64,
+               [3] = 32
+       };
+       int ps, fs;
+
+       for (ps = 0; ps < ARRAY_SIZE(ps_list); ps++) {
+               for (fs = 0; fs < ARRAY_SIZE(fs_list); fs++) {
+                       if (frequency == ps_list[ps] * fs_list[fs]) {
+                               snd_soc_write(codec, MD_CTL2,
+                                             PSs(ps) | FSs(fs));
+                               return 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u8 rate;
+       struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+       u32 rate = clk_get_rate(priv->mcko);
 
-       switch (params_rate(params)) {
-       case 7350:
-               rate = FS2;
-               break;
-       case 8000:
-               rate = 0;
-               break;
-       case 11025:
-               rate = FS2 | FS0;
-               break;
-       case 12000:
-               rate = FS0;
-               break;
-       case 14700:
-               rate = FS2 | FS1;
-               break;
-       case 16000:
-               rate = FS1;
-               break;
-       case 22050:
-               rate = FS2 | FS1 | FS0;
-               break;
-       case 24000:
-               rate = FS1 | FS0;
-               break;
-       case 29400:
-               rate = FS3 | FS2 | FS1;
-               break;
-       case 32000:
-               rate = FS3 | FS1;
-               break;
-       case 44100:
-               rate = FS3 | FS2 | FS1 | FS0;
-               break;
-       case 48000:
-               rate = FS3 | FS1 | FS0;
-               break;
-       default:
-               return -EINVAL;
-       }
-       snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
+       if (!rate)
+               rate = params_rate(params) * 256;
 
-       return 0;
+       return ak4642_set_mcko(codec, rate);
 }
 
 static int ak4642_set_bias_level(struct snd_soc_codec *codec,
@@ -532,7 +532,18 @@ static int ak4642_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
+static int ak4642_probe(struct snd_soc_codec *codec)
+{
+       struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       if (priv->mcko)
+               ak4642_set_mcko(codec, clk_get_rate(priv->mcko));
+
+       return 0;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+       .probe                  = ak4642_probe,
        .resume                 = ak4642_resume,
        .set_bias_level         = ak4642_set_bias_level,
        .controls               = ak4642_snd_controls,
@@ -580,19 +591,54 @@ static const struct ak4642_drvdata ak4648_drvdata = {
        .extended_frequencies = 1,
 };
 
+#ifdef CONFIG_COMMON_CLK
+static struct clk *ak4642_of_parse_mcko(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct clk *clk;
+       const char *clk_name = np->name;
+       const char *parent_clk_name = NULL;
+       u32 rate;
+
+       if (of_property_read_u32(np, "clock-frequency", &rate))
+               return NULL;
+
+       if (of_property_read_bool(np, "clocks"))
+               parent_clk_name = of_clk_get_parent_name(np, 0);
+
+       of_property_read_string(np, "clock-output-names", &clk_name);
+
+       clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name,
+                                     (parent_clk_name) ? 0 : CLK_IS_ROOT,
+                                     rate);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+       return clk;
+}
+#else
+#define ak4642_of_parse_mcko(d) 0
+#endif
+
 static const struct of_device_id ak4642_of_match[];
 static int ak4642_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct device_node *np = i2c->dev.of_node;
+       struct device *dev = &i2c->dev;
+       struct device_node *np = dev->of_node;
        const struct ak4642_drvdata *drvdata = NULL;
        struct regmap *regmap;
        struct ak4642_priv *priv;
+       struct clk *mcko = NULL;
 
        if (np) {
                const struct of_device_id *of_id;
 
-               of_id = of_match_device(ak4642_of_match, &i2c->dev);
+               mcko = ak4642_of_parse_mcko(dev);
+               if (IS_ERR(mcko))
+                       mcko = NULL;
+
+               of_id = of_match_device(ak4642_of_match, dev);
                if (of_id)
                        drvdata = of_id->data;
        } else {
@@ -600,15 +646,16 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
        }
 
        if (!drvdata) {
-               dev_err(&i2c->dev, "Unknown device type\n");
+               dev_err(dev, "Unknown device type\n");
                return -EINVAL;
        }
 
-       priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        priv->drvdata = drvdata;
+       priv->mcko = mcko;
 
        i2c_set_clientdata(i2c, priv);
 
@@ -616,7 +663,7 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       return snd_soc_register_codec(&i2c->dev,
+       return snd_soc_register_codec(dev,
                                      &soc_codec_dev_ak4642, &ak4642_dai, 1);
 }
 
index 8a2221ab3d10b97f5f7a97c21251264aa93eaa5b..9929efc6b9aaa4257a155e844b7feb2f91ea80f9 100644 (file)
@@ -147,6 +147,8 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
                                                   0x4f5, 0x0da);
                }
                break;
+       default:
+               break;
        }
 
        return 0;
@@ -314,6 +316,7 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "Tone Generator 2",
        "Haptics",
        "AEC",
+       "AEC2",
        "Mic Mute Mixer",
        "Noise Generator",
        "IN1L",
@@ -421,6 +424,7 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
        0x05,
        0x06,  /* Haptics */
        0x08,  /* AEC */
+       0x09,  /* AEC2 */
        0x0c,  /* Noise mixer */
        0x0d,  /* Comfort noise */
        0x10,  /* IN1L */
@@ -525,6 +529,32 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
 const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
 EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
 
+const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
+       "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
+       "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
+       "4kHz", "8kHz", "16kHz", "32kHz",
+};
+EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
+
+const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
+       0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+       0x10, 0x11, 0x12, 0x13,
+};
+EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
+
+const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
+               if (arizona_sample_rate_val[i] == rate_val)
+                       return arizona_sample_rate_text[i];
+       }
+
+       return "Illegal";
+}
+EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
+
 const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
        "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
 };
@@ -689,6 +719,15 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
                                    ARIZONA_IN_VU, val);
 }
 
+bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
+{
+       unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
+       unsigned int val = snd_soc_read(codec, reg);
+
+       return !(val & ARIZONA_IN1_MODE_MASK);
+}
+EXPORT_SYMBOL_GPL(arizona_input_analog);
+
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                  int event)
 {
@@ -725,6 +764,9 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
                if (reg == 0)
                        arizona_in_set_vu(codec, 0);
+               break;
+       default:
+               break;
        }
 
        return 0;
@@ -806,6 +848,8 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                        break;
                }
                break;
+       default:
+               break;
        }
 
        return 0;
@@ -1868,6 +1912,11 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
                if (fll->arizona->rev < 3 || sync)
                        return init_ratio;
                break;
+       case WM8998:
+       case WM1814:
+               if (sync)
+                       return init_ratio;
+               break;
        default:
                return init_ratio;
        }
index ada0a418ff4b648034841e9b36f4df598d03fac2..fea8b8ae8e1a1517929bca406f20066fa25724bb 100644 (file)
@@ -93,12 +93,17 @@ struct arizona_priv {
        bool dvfs_cached;
 };
 
-#define ARIZONA_NUM_MIXER_INPUTS 103
+#define ARIZONA_NUM_MIXER_INPUTS 104
 
 extern const unsigned int arizona_mixer_tlv[];
 extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
 extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 
+#define ARIZONA_GAINMUX_CONTROLS(name, base) \
+       SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1,            \
+                            ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,    \
+                            arizona_mixer_tlv)
+
 #define ARIZONA_MIXER_CONTROLS(name, base) \
        SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1,          \
                             ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,    \
@@ -209,8 +214,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
         .num_regs = 1 }) }
 
 #define ARIZONA_RATE_ENUM_SIZE 4
+#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
+
 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
 extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
+extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
 
 extern const struct soc_enum arizona_isrc_fsl[];
 extern const struct soc_enum arizona_isrc_fsh[];
@@ -294,4 +303,7 @@ extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
                            bool diff);
 
+extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
+
+extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
 #endif
index a9c86efb31878a343262a589facc4c5424522ae9..7278f93460c1ee1f5eb48fafaf2f95d0aa406c62 100644 (file)
@@ -12,6 +12,7 @@
  * option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
@@ -1222,23 +1223,44 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq))
+               return 0;
+
+       if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) {
+               dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+                       freq);
+               return -EINVAL;
+       }
 
        switch (clk_id) {
        case DA7213_CLKSRC_MCLK:
-               if ((freq == 32768) ||
-                   ((freq >= 5000000) && (freq <= 54000000))) {
-                       da7213->mclk_rate = freq;
-                       return 0;
-               } else {
-                       dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
-                               freq);
-                       return -EINVAL;
-               }
+               da7213->mclk_squarer_en = false;
+               break;
+       case DA7213_CLKSRC_MCLK_SQR:
+               da7213->mclk_squarer_en = true;
                break;
        default:
                dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
                return -EINVAL;
        }
+
+       da7213->clk_src = clk_id;
+
+       if (da7213->mclk) {
+               freq = clk_round_rate(da7213->mclk, freq);
+               ret = clk_set_rate(da7213->mclk, freq);
+               if (ret) {
+                       dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+                               freq);
+                       return ret;
+               }
+       }
+
+       da7213->mclk_rate = freq;
+
+       return 0;
 }
 
 /* Supported PLL input frequencies are 5MHz - 54MHz. */
@@ -1366,12 +1388,25 @@ static struct snd_soc_dai_driver da7213_dai = {
 static int da7213_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
                if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       /* MCLK */
+                       if (da7213->mclk) {
+                               ret = clk_prepare_enable(da7213->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable mclk\n");
+                                       return ret;
+                               }
+                       }
+
                        /* Enable VMID reference & master bias */
                        snd_soc_update_bits(codec, DA7213_REFERENCES,
                                            DA7213_VMID_EN | DA7213_BIAS_EN,
@@ -1382,15 +1417,127 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
                /* Disable VMID reference & master bias */
                snd_soc_update_bits(codec, DA7213_REFERENCES,
                                    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
+
+               /* MCLK */
+               if (da7213->mclk)
+                       clk_disable_unprepare(da7213->mclk);
                break;
        }
        return 0;
 }
 
+/* DT */
+static const struct of_device_id da7213_of_match[] = {
+       { .compatible = "dlg,da7213", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, da7213_of_match);
+
+static enum da7213_micbias_voltage
+       da7213_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1600:
+               return DA7213_MICBIAS_1_6V;
+       case 2200:
+               return DA7213_MICBIAS_2_2V;
+       case 2500:
+               return DA7213_MICBIAS_2_5V;
+       case 3000:
+               return DA7213_MICBIAS_3_0V;
+       default:
+               dev_warn(codec->dev, "Invalid micbias level\n");
+               return DA7213_MICBIAS_2_2V;
+       }
+}
+
+static enum da7213_dmic_data_sel
+       da7213_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "lrise_rfall")) {
+               return DA7213_DMIC_DATA_LRISE_RFALL;
+       } else if (!strcmp(str, "lfall_rrise")) {
+               return DA7213_DMIC_DATA_LFALL_RRISE;
+       } else {
+               dev_warn(codec->dev, "Invalid DMIC data select type\n");
+               return DA7213_DMIC_DATA_LRISE_RFALL;
+       }
+}
+
+static enum da7213_dmic_samplephase
+       da7213_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "on_clkedge")) {
+               return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+       } else if (!strcmp(str, "between_clkedge")) {
+               return DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+       } else {
+               dev_warn(codec->dev, "Invalid DMIC sample phase\n");
+               return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+       }
+}
+
+static enum da7213_dmic_clk_rate
+       da7213_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1500000:
+               return DA7213_DMIC_CLK_1_5MHZ;
+       case 3000000:
+               return DA7213_DMIC_CLK_3_0MHZ;
+       default:
+               dev_warn(codec->dev, "Invalid DMIC clock rate\n");
+               return DA7213_DMIC_CLK_1_5MHZ;
+       }
+}
+
+static struct da7213_platform_data
+       *da7213_of_to_pdata(struct snd_soc_codec *codec)
+{
+       struct device_node *np = codec->dev->of_node;
+       struct da7213_platform_data *pdata;
+       const char *of_str;
+       u32 of_val32;
+
+       pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+               return NULL;
+       }
+
+       if (of_property_read_u32(np, "dlg,micbias1-lvl", &of_val32) >= 0)
+               pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, of_val32);
+       else
+               pdata->micbias1_lvl = DA7213_MICBIAS_2_2V;
+
+       if (of_property_read_u32(np, "dlg,micbias2-lvl", &of_val32) >= 0)
+               pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, of_val32);
+       else
+               pdata->micbias2_lvl = DA7213_MICBIAS_2_2V;
+
+       if (!of_property_read_string(np, "dlg,dmic-data-sel", &of_str))
+               pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, of_str);
+       else
+               pdata->dmic_data_sel = DA7213_DMIC_DATA_LRISE_RFALL;
+
+       if (!of_property_read_string(np, "dlg,dmic-samplephase", &of_str))
+               pdata->dmic_samplephase =
+                       da7213_of_dmic_samplephase(codec, of_str);
+       else
+               pdata->dmic_samplephase = DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+
+       if (of_property_read_u32(np, "dlg,dmic-clkrate", &of_val32) >= 0)
+               pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, of_val32);
+       else
+               pdata->dmic_clk_rate = DA7213_DMIC_CLK_3_0MHZ;
+
+       return pdata;
+}
+
+
 static int da7213_probe(struct snd_soc_codec *codec)
 {
        struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
-       struct da7213_platform_data *pdata = da7213->pdata;
 
        /* Default to using ALC auto offset calibration mode. */
        snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
@@ -1450,8 +1597,15 @@ static int da7213_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, DA7213_LINE_CTRL,
                            DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE);
 
+       /* Handle DT/Platform data */
+       if (codec->dev->of_node)
+               da7213->pdata = da7213_of_to_pdata(codec);
+       else
+               da7213->pdata = dev_get_platdata(codec->dev);
+
        /* Set platform data values */
        if (da7213->pdata) {
+               struct da7213_platform_data *pdata = da7213->pdata;
                u8 micbias_lvl = 0, dmic_cfg = 0;
 
                /* Set Mic Bias voltages */
@@ -1503,10 +1657,17 @@ static int da7213_probe(struct snd_soc_codec *codec)
                                    DA7213_DMIC_DATA_SEL_MASK |
                                    DA7213_DMIC_SAMPLEPHASE_MASK |
                                    DA7213_DMIC_CLK_RATE_MASK, dmic_cfg);
+       }
 
-               /* Set MCLK squaring */
-               da7213->mclk_squarer_en = pdata->mclk_squaring;
+       /* Check if MCLK provided */
+       da7213->mclk = devm_clk_get(codec->dev, "mclk");
+       if (IS_ERR(da7213->mclk)) {
+               if (PTR_ERR(da7213->mclk) != -ENOENT)
+                       return PTR_ERR(da7213->mclk);
+               else
+                       da7213->mclk = NULL;
        }
+
        return 0;
 }
 
@@ -1537,7 +1698,6 @@ static int da7213_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct da7213_priv *da7213;
-       struct da7213_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret;
 
        da7213 = devm_kzalloc(&i2c->dev, sizeof(struct da7213_priv),
@@ -1545,9 +1705,6 @@ static int da7213_i2c_probe(struct i2c_client *i2c,
        if (!da7213)
                return -ENOMEM;
 
-       if (pdata)
-               da7213->pdata = pdata;
-
        i2c_set_clientdata(i2c, da7213);
 
        da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config);
@@ -1582,6 +1739,7 @@ MODULE_DEVICE_TABLE(i2c, da7213_i2c_id);
 static struct i2c_driver da7213_i2c_driver = {
        .driver = {
                .name = "da7213",
+               .of_match_table = of_match_ptr(da7213_of_match),
        },
        .probe          = da7213_i2c_probe,
        .remove         = da7213_remove,
index 9cb9ddd012826d4391f7f2669a11294163f16925..030fd691b07626ab599fe53bd0b3a1903268b94b 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _DA7213_H
 #define _DA7213_H
 
+#include <linux/clk.h>
 #include <linux/regmap.h>
 #include <sound/da7213.h>
 
 #define DA7213_PLL_INDIV_20_40_MHZ_VAL 8
 #define DA7213_PLL_INDIV_40_54_MHZ_VAL 16
 
-enum clk_src {
-       DA7213_CLKSRC_MCLK
+enum da7213_clk_src {
+       DA7213_CLKSRC_MCLK = 0,
+       DA7213_CLKSRC_MCLK_SQR,
 };
 
 /* Codec private data */
 struct da7213_priv {
        struct regmap *regmap;
+       struct clk *mclk;
        unsigned int mclk_rate;
+       int clk_src;
        bool master;
        bool mclk_squarer_en;
        bool srm_en;
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
new file mode 100644 (file)
index 0000000..9459593
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/da7219.h>
+
+#include "da7219.h"
+#include "da7219-aad.h"
+
+
+/*
+ * Detection control
+ */
+
+void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       da7219->aad->jack = jack;
+       da7219->aad->jack_inserted = false;
+
+       /* Send an initial empty report */
+       snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
+
+       /* Enable/Disable jack detection */
+       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+                           DA7219_ACCDET_EN_MASK,
+                           (jack ? DA7219_ACCDET_EN_MASK : 0));
+}
+EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
+
+/*
+ * Button/HPTest work
+ */
+
+static void da7219_aad_btn_det_work(struct work_struct *work)
+{
+       struct da7219_aad_priv *da7219_aad =
+               container_of(work, struct da7219_aad_priv, btn_det_work);
+       struct snd_soc_codec *codec = da7219_aad->codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       u8 statusa, micbias_ctrl;
+       bool micbias_up = false;
+       int retries = 0;
+
+       /* Drive headphones/lineout */
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_OE_MASK,
+                           DA7219_HP_L_AMP_OE_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_OE_MASK,
+                           DA7219_HP_R_AMP_OE_MASK);
+
+       /* Make sure mic bias is up */
+       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+       snd_soc_dapm_sync(dapm);
+
+       do {
+               statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
+               if (statusa & DA7219_MICBIAS_UP_STS_MASK)
+                       micbias_up = true;
+               else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
+                       msleep(DA7219_AAD_MICBIAS_CHK_DELAY);
+       } while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
+
+       if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
+               dev_warn(codec->dev, "Mic bias status check timed out");
+
+       /*
+        * Mic bias pulse required to enable mic, must be done before enabling
+        * button detection to prevent erroneous button readings.
+        */
+       if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
+               /* Pulse higher level voltage */
+               micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
+               snd_soc_update_bits(codec, DA7219_MICBIAS_CTRL,
+                                   DA7219_MICBIAS1_LEVEL_MASK,
+                                   da7219_aad->micbias_pulse_lvl);
+               msleep(da7219_aad->micbias_pulse_time);
+               snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_ctrl);
+
+       }
+
+       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+                           DA7219_BUTTON_CONFIG_MASK,
+                           da7219_aad->btn_cfg);
+}
+
+static void da7219_aad_hptest_work(struct work_struct *work)
+{
+       struct da7219_aad_priv *da7219_aad =
+               container_of(work, struct da7219_aad_priv, hptest_work);
+       struct snd_soc_codec *codec = da7219_aad->codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       u16 tonegen_freq_hptest;
+       u8 accdet_cfg8;
+       int report = 0;
+
+       /* Lock DAPM and any Kcontrols that are affected by this test */
+       snd_soc_dapm_mutex_lock(dapm);
+       mutex_lock(&da7219->lock);
+
+       /* Bypass cache so it saves current settings */
+       regcache_cache_bypass(da7219->regmap, true);
+
+       /* Make sure Tone Generator is disabled */
+       snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
+
+       /* Enable HPTest block, 1KOhms check */
+       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
+                           DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
+                           DA7219_HPTEST_EN_MASK |
+                           DA7219_HPTEST_RES_SEL_1KOHMS);
+
+       /* Set gains to 0db */
+       snd_soc_write(codec, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+       snd_soc_write(codec, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+       snd_soc_write(codec, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
+       snd_soc_write(codec, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
+
+       /* Disable DAC filters, EQs and soft mute */
+       snd_soc_update_bits(codec, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
+                           0);
+       snd_soc_update_bits(codec, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
+                           0);
+       snd_soc_update_bits(codec, DA7219_DAC_FILTERS5,
+                           DA7219_DAC_SOFTMUTE_EN_MASK, 0);
+
+       /* Enable HP left & right paths */
+       snd_soc_update_bits(codec, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
+                           DA7219_CP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_DIG_ROUTING_DAC,
+                           DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
+                           DA7219_DAC_L_SRC_TONEGEN |
+                           DA7219_DAC_R_SRC_TONEGEN);
+       snd_soc_update_bits(codec, DA7219_DAC_L_CTRL,
+                           DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
+                           DA7219_DAC_L_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_DAC_R_CTRL,
+                           DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
+                           DA7219_DAC_R_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_MIXOUT_L_SELECT,
+                           DA7219_MIXOUT_L_MIX_SELECT_MASK,
+                           DA7219_MIXOUT_L_MIX_SELECT_MASK);
+       snd_soc_update_bits(codec, DA7219_MIXOUT_R_SELECT,
+                           DA7219_MIXOUT_R_MIX_SELECT_MASK,
+                           DA7219_MIXOUT_R_MIX_SELECT_MASK);
+       snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1L,
+                           DA7219_OUTFILT_ST_1L_SRC_MASK,
+                           DA7219_DMIX_ST_SRC_OUTFILT1L);
+       snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1R,
+                           DA7219_OUTFILT_ST_1R_SRC_MASK,
+                           DA7219_DMIX_ST_SRC_OUTFILT1R);
+       snd_soc_update_bits(codec, DA7219_MIXOUT_L_CTRL,
+                           DA7219_MIXOUT_L_AMP_EN_MASK,
+                           DA7219_MIXOUT_L_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
+                           DA7219_MIXOUT_R_AMP_EN_MASK,
+                           DA7219_MIXOUT_R_AMP_EN_MASK);
+       snd_soc_write(codec, DA7219_HP_L_CTRL,
+                     DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
+       snd_soc_write(codec, DA7219_HP_R_CTRL,
+                     DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+
+       /* Configure & start Tone Generator */
+       snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
+       tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
+       regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
+                        &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
+       snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
+                           DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
+                           DA7219_SWG_SEL_SRAMP |
+                           DA7219_TONE_GEN_GAIN_MINUS_15DB);
+       snd_soc_write(codec, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
+
+       msleep(DA7219_AAD_HPTEST_PERIOD);
+
+       /* Grab comparator reading */
+       accdet_cfg8 = snd_soc_read(codec, DA7219_ACCDET_CONFIG_8);
+       if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
+               report |= SND_JACK_HEADPHONE;
+       else
+               report |= SND_JACK_LINEOUT;
+
+       /* Stop tone generator */
+       snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
+
+       msleep(DA7219_AAD_HPTEST_PERIOD);
+
+       /* Restore original settings from cache */
+       regcache_mark_dirty(da7219->regmap);
+       regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
+                            DA7219_HP_R_CTRL);
+       regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
+                            DA7219_MIXOUT_R_CTRL);
+       regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
+                            DA7219_DROUTING_ST_OUTFILT_1R);
+       regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
+                            DA7219_MIXOUT_R_SELECT);
+       regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
+                            DA7219_DAC_R_CTRL);
+       regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
+                            DA7219_DIG_ROUTING_DAC);
+       regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
+       regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
+                            DA7219_DAC_FILTERS5);
+       regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
+                            DA7219_DAC_FILTERS1);
+       regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
+                            DA7219_HP_R_GAIN);
+       regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
+                            DA7219_DAC_R_GAIN);
+       regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
+                            DA7219_TONE_GEN_ON_PER);
+       regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
+                            DA7219_TONE_GEN_FREQ1_U);
+       regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
+                            DA7219_TONE_GEN_CFG2);
+
+       regcache_cache_bypass(da7219->regmap, false);
+
+       /* Disable HPTest block */
+       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
+                           DA7219_HPTEST_EN_MASK, 0);
+
+       /* Drive Headphones/lineout */
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
+                           DA7219_HP_L_AMP_OE_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
+                           DA7219_HP_R_AMP_OE_MASK);
+
+       mutex_unlock(&da7219->lock);
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       /*
+        * Only send report if jack hasn't been removed during process,
+        * otherwise it's invalid and we drop it.
+        */
+       if (da7219_aad->jack_inserted)
+               snd_soc_jack_report(da7219_aad->jack, report,
+                                   SND_JACK_HEADSET | SND_JACK_LINEOUT);
+}
+
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
+{
+       struct da7219_aad_priv *da7219_aad = data;
+       struct snd_soc_codec *codec = da7219_aad->codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       u8 events[DA7219_AAD_IRQ_REG_MAX];
+       u8 statusa;
+       int i, report = 0, mask = 0;
+
+       /* Read current IRQ events */
+       regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
+                        events, DA7219_AAD_IRQ_REG_MAX);
+
+       if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
+               return IRQ_NONE;
+
+       /* Read status register for jack insertion & type status */
+       statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
+
+       /* Clear events */
+       regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
+                         events, DA7219_AAD_IRQ_REG_MAX);
+
+       dev_dbg(codec->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
+               events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
+               statusa);
+
+       if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
+               /* Jack Insertion */
+               if (events[DA7219_AAD_IRQ_REG_A] &
+                   DA7219_E_JACK_INSERTED_MASK) {
+                       report |= SND_JACK_MECHANICAL;
+                       mask |= SND_JACK_MECHANICAL;
+                       da7219_aad->jack_inserted = true;
+               }
+
+               /* Jack type detection */
+               if (events[DA7219_AAD_IRQ_REG_A] &
+                   DA7219_E_JACK_DETECT_COMPLETE_MASK) {
+                       /*
+                        * If 4-pole, then enable button detection, else perform
+                        * HP impedance test to determine output type to report.
+                        *
+                        * We schedule work here as the tasks themselves can
+                        * take time to complete, and in particular for hptest
+                        * we want to be able to check if the jack was removed
+                        * during the procedure as this will invalidate the
+                        * result. By doing this as work, the IRQ thread can
+                        * handle a removal, and we can check at the end of
+                        * hptest if we have a valid result or not.
+                        */
+                       if (statusa & DA7219_JACK_TYPE_STS_MASK) {
+                               report |= SND_JACK_HEADSET;
+                               mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT;
+                               schedule_work(&da7219_aad->btn_det_work);
+                       } else {
+                               schedule_work(&da7219_aad->hptest_work);
+                       }
+               }
+
+               /* Button support for 4-pole jack */
+               if (statusa & DA7219_JACK_TYPE_STS_MASK) {
+                       for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
+                               /* Button Press */
+                               if (events[DA7219_AAD_IRQ_REG_B] &
+                                   (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
+                                       report |= SND_JACK_BTN_0 >> i;
+                                       mask |= SND_JACK_BTN_0 >> i;
+                               }
+                       }
+                       snd_soc_jack_report(da7219_aad->jack, report, mask);
+
+                       for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
+                               /* Button Release */
+                               if (events[DA7219_AAD_IRQ_REG_B] &
+                                   (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
+                                       report &= ~(SND_JACK_BTN_0 >> i);
+                                       mask |= SND_JACK_BTN_0 >> i;
+                               }
+                       }
+               }
+       } else {
+               /* Jack removal */
+               if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
+                       report = 0;
+                       mask |= DA7219_AAD_REPORT_ALL_MASK;
+                       da7219_aad->jack_inserted = false;
+
+                       /* Un-drive headphones/lineout */
+                       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                                           DA7219_HP_R_AMP_OE_MASK, 0);
+                       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                                           DA7219_HP_L_AMP_OE_MASK, 0);
+
+                       /* Ensure button detection disabled */
+                       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+                                           DA7219_BUTTON_CONFIG_MASK, 0);
+
+                       /* Disable mic bias */
+                       snd_soc_dapm_disable_pin(dapm, "Mic Bias");
+                       snd_soc_dapm_sync(dapm);
+
+                       /* Cancel any pending work */
+                       cancel_work_sync(&da7219_aad->btn_det_work);
+                       cancel_work_sync(&da7219_aad->hptest_work);
+               }
+       }
+
+       snd_soc_jack_report(da7219_aad->jack, report, mask);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * DT to pdata conversion
+ */
+
+static enum da7219_aad_micbias_pulse_lvl
+       da7219_aad_of_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 2800:
+               return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
+       case 2900:
+               return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
+       default:
+               dev_warn(codec->dev, "Invalid micbias pulse level");
+               return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
+       }
+}
+
+static enum da7219_aad_btn_cfg
+       da7219_aad_of_btn_cfg(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 2:
+               return DA7219_AAD_BTN_CFG_2MS;
+       case 5:
+               return DA7219_AAD_BTN_CFG_5MS;
+       case 10:
+               return DA7219_AAD_BTN_CFG_10MS;
+       case 50:
+               return DA7219_AAD_BTN_CFG_50MS;
+       case 100:
+               return DA7219_AAD_BTN_CFG_100MS;
+       case 200:
+               return DA7219_AAD_BTN_CFG_200MS;
+       case 500:
+               return DA7219_AAD_BTN_CFG_500MS;
+       default:
+               dev_warn(codec->dev, "Invalid button config");
+               return DA7219_AAD_BTN_CFG_10MS;
+       }
+}
+
+static enum da7219_aad_mic_det_thr
+       da7219_aad_of_mic_det_thr(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 200:
+               return DA7219_AAD_MIC_DET_THR_200_OHMS;
+       case 500:
+               return DA7219_AAD_MIC_DET_THR_500_OHMS;
+       case 750:
+               return DA7219_AAD_MIC_DET_THR_750_OHMS;
+       case 1000:
+               return DA7219_AAD_MIC_DET_THR_1000_OHMS;
+       default:
+               dev_warn(codec->dev, "Invalid mic detect threshold");
+               return DA7219_AAD_MIC_DET_THR_500_OHMS;
+       }
+}
+
+static enum da7219_aad_jack_ins_deb
+       da7219_aad_of_jack_ins_deb(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 5:
+               return DA7219_AAD_JACK_INS_DEB_5MS;
+       case 10:
+               return DA7219_AAD_JACK_INS_DEB_10MS;
+       case 20:
+               return DA7219_AAD_JACK_INS_DEB_20MS;
+       case 50:
+               return DA7219_AAD_JACK_INS_DEB_50MS;
+       case 100:
+               return DA7219_AAD_JACK_INS_DEB_100MS;
+       case 200:
+               return DA7219_AAD_JACK_INS_DEB_200MS;
+       case 500:
+               return DA7219_AAD_JACK_INS_DEB_500MS;
+       case 1000:
+               return DA7219_AAD_JACK_INS_DEB_1S;
+       default:
+               dev_warn(codec->dev, "Invalid jack insert debounce");
+               return DA7219_AAD_JACK_INS_DEB_20MS;
+       }
+}
+
+static enum da7219_aad_jack_det_rate
+       da7219_aad_of_jack_det_rate(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "32ms_64ms")) {
+               return DA7219_AAD_JACK_DET_RATE_32_64MS;
+       } else if (!strcmp(str, "64ms_128ms")) {
+               return DA7219_AAD_JACK_DET_RATE_64_128MS;
+       } else if (!strcmp(str, "128ms_256ms")) {
+               return DA7219_AAD_JACK_DET_RATE_128_256MS;
+       } else if (!strcmp(str, "256ms_512ms")) {
+               return DA7219_AAD_JACK_DET_RATE_256_512MS;
+       } else {
+               dev_warn(codec->dev, "Invalid jack detect rate");
+               return DA7219_AAD_JACK_DET_RATE_256_512MS;
+       }
+}
+
+static enum da7219_aad_jack_rem_deb
+       da7219_aad_of_jack_rem_deb(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1:
+               return DA7219_AAD_JACK_REM_DEB_1MS;
+       case 5:
+               return DA7219_AAD_JACK_REM_DEB_5MS;
+       case 10:
+               return DA7219_AAD_JACK_REM_DEB_10MS;
+       case 20:
+               return DA7219_AAD_JACK_REM_DEB_20MS;
+       default:
+               dev_warn(codec->dev, "Invalid jack removal debounce");
+               return DA7219_AAD_JACK_REM_DEB_1MS;
+       }
+}
+
+static enum da7219_aad_btn_avg
+       da7219_aad_of_btn_avg(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1:
+               return DA7219_AAD_BTN_AVG_1;
+       case 2:
+               return DA7219_AAD_BTN_AVG_2;
+       case 4:
+               return DA7219_AAD_BTN_AVG_4;
+       case 8:
+               return DA7219_AAD_BTN_AVG_8;
+       default:
+               dev_warn(codec->dev, "Invalid button average value");
+               return DA7219_AAD_BTN_AVG_2;
+       }
+}
+
+static enum da7219_aad_adc_1bit_rpt
+       da7219_aad_of_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1:
+               return DA7219_AAD_ADC_1BIT_RPT_1;
+       case 2:
+               return DA7219_AAD_ADC_1BIT_RPT_2;
+       case 4:
+               return DA7219_AAD_ADC_1BIT_RPT_4;
+       case 8:
+               return DA7219_AAD_ADC_1BIT_RPT_8;
+       default:
+               dev_warn(codec->dev, "Invalid ADC 1-bit repeat value");
+               return DA7219_AAD_ADC_1BIT_RPT_1;
+       }
+}
+
+static struct da7219_aad_pdata *da7219_aad_of_to_pdata(struct snd_soc_codec *codec)
+{
+       struct device_node *np = codec->dev->of_node;
+       struct device_node *aad_np = of_find_node_by_name(np, "da7219_aad");
+       struct da7219_aad_pdata *aad_pdata;
+       const char *of_str;
+       u32 of_val32;
+
+       if (!aad_np)
+               return NULL;
+
+       aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL);
+       if (!aad_pdata)
+               goto out;
+
+       aad_pdata->irq = irq_of_parse_and_map(np, 0);
+
+       if (of_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
+                                &of_val32) >= 0)
+               aad_pdata->micbias_pulse_lvl =
+                       da7219_aad_of_micbias_pulse_lvl(codec, of_val32);
+       else
+               aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
+
+       if (of_property_read_u32(aad_np, "dlg,micbias-pulse-time",
+                                &of_val32) >= 0)
+               aad_pdata->micbias_pulse_time = of_val32;
+
+       if (of_property_read_u32(aad_np, "dlg,btn-cfg", &of_val32) >= 0)
+               aad_pdata->btn_cfg = da7219_aad_of_btn_cfg(codec, of_val32);
+       else
+               aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
+
+       if (of_property_read_u32(aad_np, "dlg,mic-det-thr", &of_val32) >= 0)
+               aad_pdata->mic_det_thr =
+                       da7219_aad_of_mic_det_thr(codec, of_val32);
+       else
+               aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
+
+       if (of_property_read_u32(aad_np, "dlg,jack-ins-deb", &of_val32) >= 0)
+               aad_pdata->jack_ins_deb =
+                       da7219_aad_of_jack_ins_deb(codec, of_val32);
+       else
+               aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
+
+       if (!of_property_read_string(aad_np, "dlg,jack-det-rate", &of_str))
+               aad_pdata->jack_det_rate =
+                       da7219_aad_of_jack_det_rate(codec, of_str);
+       else
+               aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
+
+       if (of_property_read_u32(aad_np, "dlg,jack-rem-deb", &of_val32) >= 0)
+               aad_pdata->jack_rem_deb =
+                       da7219_aad_of_jack_rem_deb(codec, of_val32);
+       else
+               aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
+
+       if (of_property_read_u32(aad_np, "dlg,a-d-btn-thr", &of_val32) >= 0)
+               aad_pdata->a_d_btn_thr = (u8) of_val32;
+       else
+               aad_pdata->a_d_btn_thr = 0xA;
+
+       if (of_property_read_u32(aad_np, "dlg,d-b-btn-thr", &of_val32) >= 0)
+               aad_pdata->d_b_btn_thr = (u8) of_val32;
+       else
+               aad_pdata->d_b_btn_thr = 0x16;
+
+       if (of_property_read_u32(aad_np, "dlg,b-c-btn-thr", &of_val32) >= 0)
+               aad_pdata->b_c_btn_thr = (u8) of_val32;
+       else
+               aad_pdata->b_c_btn_thr = 0x21;
+
+       if (of_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &of_val32) >= 0)
+               aad_pdata->c_mic_btn_thr = (u8) of_val32;
+       else
+               aad_pdata->c_mic_btn_thr = 0x3E;
+
+       if (of_property_read_u32(aad_np, "dlg,btn-avg", &of_val32) >= 0)
+               aad_pdata->btn_avg = da7219_aad_of_btn_avg(codec, of_val32);
+       else
+               aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
+
+       if (of_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &of_val32) >= 0)
+               aad_pdata->adc_1bit_rpt =
+                       da7219_aad_of_adc_1bit_rpt(codec, of_val32);
+       else
+               aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
+
+out:
+       of_node_put(aad_np);
+
+       return aad_pdata;
+}
+
+static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct da7219_aad_priv *da7219_aad = da7219->aad;
+       struct da7219_pdata *pdata = da7219->pdata;
+
+       if ((pdata) && (pdata->aad_pdata)) {
+               struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
+               u8 cfg, mask;
+
+               da7219_aad->irq = aad_pdata->irq;
+
+               switch (aad_pdata->micbias_pulse_lvl) {
+               case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
+               case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
+                       da7219_aad->micbias_pulse_lvl =
+                               (aad_pdata->micbias_pulse_lvl <<
+                                DA7219_MICBIAS1_LEVEL_SHIFT);
+                       break;
+               default:
+                       break;
+               }
+
+               da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
+
+               switch (aad_pdata->btn_cfg) {
+               case DA7219_AAD_BTN_CFG_2MS:
+               case DA7219_AAD_BTN_CFG_5MS:
+               case DA7219_AAD_BTN_CFG_10MS:
+               case DA7219_AAD_BTN_CFG_50MS:
+               case DA7219_AAD_BTN_CFG_100MS:
+               case DA7219_AAD_BTN_CFG_200MS:
+               case DA7219_AAD_BTN_CFG_500MS:
+                       da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<
+                                               DA7219_BUTTON_CONFIG_SHIFT);
+               }
+
+               cfg = 0;
+               mask = 0;
+               switch (aad_pdata->mic_det_thr) {
+               case DA7219_AAD_MIC_DET_THR_200_OHMS:
+               case DA7219_AAD_MIC_DET_THR_500_OHMS:
+               case DA7219_AAD_MIC_DET_THR_750_OHMS:
+               case DA7219_AAD_MIC_DET_THR_1000_OHMS:
+                       cfg |= (aad_pdata->mic_det_thr <<
+                               DA7219_MIC_DET_THRESH_SHIFT);
+                       mask |= DA7219_MIC_DET_THRESH_MASK;
+               }
+               snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg);
+
+               cfg = 0;
+               mask = 0;
+               switch (aad_pdata->jack_ins_deb) {
+               case DA7219_AAD_JACK_INS_DEB_5MS:
+               case DA7219_AAD_JACK_INS_DEB_10MS:
+               case DA7219_AAD_JACK_INS_DEB_20MS:
+               case DA7219_AAD_JACK_INS_DEB_50MS:
+               case DA7219_AAD_JACK_INS_DEB_100MS:
+               case DA7219_AAD_JACK_INS_DEB_200MS:
+               case DA7219_AAD_JACK_INS_DEB_500MS:
+               case DA7219_AAD_JACK_INS_DEB_1S:
+                       cfg |= (aad_pdata->jack_ins_deb <<
+                               DA7219_JACKDET_DEBOUNCE_SHIFT);
+                       mask |= DA7219_JACKDET_DEBOUNCE_MASK;
+               }
+               switch (aad_pdata->jack_det_rate) {
+               case DA7219_AAD_JACK_DET_RATE_32_64MS:
+               case DA7219_AAD_JACK_DET_RATE_64_128MS:
+               case DA7219_AAD_JACK_DET_RATE_128_256MS:
+               case DA7219_AAD_JACK_DET_RATE_256_512MS:
+                       cfg |= (aad_pdata->jack_det_rate <<
+                               DA7219_JACK_DETECT_RATE_SHIFT);
+                       mask |= DA7219_JACK_DETECT_RATE_MASK;
+               }
+               switch (aad_pdata->jack_rem_deb) {
+               case DA7219_AAD_JACK_REM_DEB_1MS:
+               case DA7219_AAD_JACK_REM_DEB_5MS:
+               case DA7219_AAD_JACK_REM_DEB_10MS:
+               case DA7219_AAD_JACK_REM_DEB_20MS:
+                       cfg |= (aad_pdata->jack_rem_deb <<
+                               DA7219_JACKDET_REM_DEB_SHIFT);
+                       mask |= DA7219_JACKDET_REM_DEB_MASK;
+               }
+               snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg);
+
+               snd_soc_write(codec, DA7219_ACCDET_CONFIG_3,
+                             aad_pdata->a_d_btn_thr);
+               snd_soc_write(codec, DA7219_ACCDET_CONFIG_4,
+                             aad_pdata->d_b_btn_thr);
+               snd_soc_write(codec, DA7219_ACCDET_CONFIG_5,
+                             aad_pdata->b_c_btn_thr);
+               snd_soc_write(codec, DA7219_ACCDET_CONFIG_6,
+                             aad_pdata->c_mic_btn_thr);
+
+               cfg = 0;
+               mask = 0;
+               switch (aad_pdata->btn_avg) {
+               case DA7219_AAD_BTN_AVG_1:
+               case DA7219_AAD_BTN_AVG_2:
+               case DA7219_AAD_BTN_AVG_4:
+               case DA7219_AAD_BTN_AVG_8:
+                       cfg |= (aad_pdata->btn_avg <<
+                               DA7219_BUTTON_AVERAGE_SHIFT);
+                       mask |= DA7219_BUTTON_AVERAGE_MASK;
+               }
+               switch (aad_pdata->adc_1bit_rpt) {
+               case DA7219_AAD_ADC_1BIT_RPT_1:
+               case DA7219_AAD_ADC_1BIT_RPT_2:
+               case DA7219_AAD_ADC_1BIT_RPT_4:
+               case DA7219_AAD_ADC_1BIT_RPT_8:
+                       cfg |= (aad_pdata->adc_1bit_rpt <<
+                              DA7219_ADC_1_BIT_REPEAT_SHIFT);
+                       mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
+               }
+               snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg);
+       }
+}
+
+
+/*
+ * Init/Exit
+ */
+
+int da7219_aad_init(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct da7219_aad_priv *da7219_aad;
+       u8 mask[DA7219_AAD_IRQ_REG_MAX];
+       int ret;
+
+       da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL);
+       if (!da7219_aad)
+               return -ENOMEM;
+
+       da7219->aad = da7219_aad;
+       da7219_aad->codec = codec;
+
+       /* Handle any DT/platform data */
+       if ((codec->dev->of_node) && (da7219->pdata))
+               da7219->pdata->aad_pdata = da7219_aad_of_to_pdata(codec);
+
+       da7219_aad_handle_pdata(codec);
+
+       /* Disable button detection */
+       snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+                           DA7219_BUTTON_CONFIG_MASK, 0);
+
+       INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
+       INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
+
+       ret = request_threaded_irq(da7219_aad->irq, NULL,
+                                  da7219_aad_irq_thread,
+                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                  "da7219-aad", da7219_aad);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+               return ret;
+       }
+
+       /* Unmask AAD IRQs */
+       memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
+       regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
+                         &mask, DA7219_AAD_IRQ_REG_MAX);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(da7219_aad_init);
+
+void da7219_aad_exit(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct da7219_aad_priv *da7219_aad = da7219->aad;
+       u8 mask[DA7219_AAD_IRQ_REG_MAX];
+
+       /* Mask off AAD IRQs */
+       memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
+       regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
+                         mask, DA7219_AAD_IRQ_REG_MAX);
+
+       free_irq(da7219_aad->irq, da7219_aad);
+
+       cancel_work_sync(&da7219_aad->btn_det_work);
+       cancel_work_sync(&da7219_aad->hptest_work);
+}
+EXPORT_SYMBOL_GPL(da7219_aad_exit);
+
+MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
new file mode 100644 (file)
index 0000000..4fccf67
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * da7219-aad.h - DA7322 ASoC AAD Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_AAD_H
+#define __DA7219_AAD_H
+
+#include <linux/timer.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/da7219-aad.h>
+
+/*
+ * Registers
+ */
+
+#define DA7219_ACCDET_STATUS_A         0xC0
+#define DA7219_ACCDET_STATUS_B         0xC1
+#define DA7219_ACCDET_IRQ_EVENT_A      0xC2
+#define DA7219_ACCDET_IRQ_EVENT_B      0xC3
+#define DA7219_ACCDET_IRQ_MASK_A       0xC4
+#define DA7219_ACCDET_IRQ_MASK_B       0xC5
+#define DA7219_ACCDET_CONFIG_1         0xC6
+#define DA7219_ACCDET_CONFIG_2         0xC7
+#define DA7219_ACCDET_CONFIG_3         0xC8
+#define DA7219_ACCDET_CONFIG_4         0xC9
+#define DA7219_ACCDET_CONFIG_5         0xCA
+#define DA7219_ACCDET_CONFIG_6         0xCB
+#define DA7219_ACCDET_CONFIG_7         0xCC
+#define DA7219_ACCDET_CONFIG_8         0xCD
+
+
+/*
+ * Bit Fields
+ */
+
+/* DA7219_ACCDET_STATUS_A = 0xC0 */
+#define DA7219_JACK_INSERTION_STS_SHIFT        0
+#define DA7219_JACK_INSERTION_STS_MASK (0x1 << 0)
+#define DA7219_JACK_TYPE_STS_SHIFT     1
+#define DA7219_JACK_TYPE_STS_MASK      (0x1 << 1)
+#define DA7219_JACK_PIN_ORDER_STS_SHIFT        2
+#define DA7219_JACK_PIN_ORDER_STS_MASK (0x1 << 2)
+#define DA7219_MICBIAS_UP_STS_SHIFT    3
+#define DA7219_MICBIAS_UP_STS_MASK     (0x1 << 3)
+
+/* DA7219_ACCDET_STATUS_B = 0xC1 */
+#define DA7219_BUTTON_TYPE_STS_SHIFT   0
+#define DA7219_BUTTON_TYPE_STS_MASK    (0xFF << 0)
+
+/* DA7219_ACCDET_IRQ_EVENT_A = 0xC2 */
+#define DA7219_E_JACK_INSERTED_SHIFT           0
+#define DA7219_E_JACK_INSERTED_MASK            (0x1 << 0)
+#define DA7219_E_JACK_REMOVED_SHIFT            1
+#define DA7219_E_JACK_REMOVED_MASK             (0x1 << 1)
+#define DA7219_E_JACK_DETECT_COMPLETE_SHIFT    2
+#define DA7219_E_JACK_DETECT_COMPLETE_MASK     (0x1 << 2)
+
+/* DA7219_ACCDET_IRQ_EVENT_B = 0xC3 */
+#define DA7219_E_BUTTON_A_PRESSED_SHIFT                0
+#define DA7219_E_BUTTON_A_PRESSED_MASK         (0x1 << 0)
+#define DA7219_E_BUTTON_B_PRESSED_SHIFT                1
+#define DA7219_E_BUTTON_B_PRESSED_MASK         (0x1 << 1)
+#define DA7219_E_BUTTON_C_PRESSED_SHIFT                2
+#define DA7219_E_BUTTON_C_PRESSED_MASK         (0x1 << 2)
+#define DA7219_E_BUTTON_D_PRESSED_SHIFT                3
+#define DA7219_E_BUTTON_D_PRESSED_MASK         (0x1 << 3)
+#define DA7219_E_BUTTON_D_RELEASED_SHIFT       4
+#define DA7219_E_BUTTON_D_RELEASED_MASK                (0x1 << 4)
+#define DA7219_E_BUTTON_C_RELEASED_SHIFT       5
+#define DA7219_E_BUTTON_C_RELEASED_MASK                (0x1 << 5)
+#define DA7219_E_BUTTON_B_RELEASED_SHIFT       6
+#define DA7219_E_BUTTON_B_RELEASED_MASK                (0x1 << 6)
+#define DA7219_E_BUTTON_A_RELEASED_SHIFT       7
+#define DA7219_E_BUTTON_A_RELEASED_MASK                (0x1 << 7)
+
+/* DA7219_ACCDET_IRQ_MASK_A = 0xC4 */
+#define DA7219_M_JACK_INSERTED_SHIFT           0
+#define DA7219_M_JACK_INSERTED_MASK            (0x1 << 0)
+#define DA7219_M_JACK_REMOVED_SHIFT            1
+#define DA7219_M_JACK_REMOVED_MASK             (0x1 << 1)
+#define DA7219_M_JACK_DETECT_COMPLETE_SHIFT    2
+#define DA7219_M_JACK_DETECT_COMPLETE_MASK     (0x1 << 2)
+
+/* DA7219_ACCDET_IRQ_MASK_B = 0xC5 */
+#define DA7219_M_BUTTON_A_PRESSED_SHIFT                0
+#define DA7219_M_BUTTON_A_PRESSED_MASK         (0x1 << 0)
+#define DA7219_M_BUTTON_B_PRESSED_SHIFT                1
+#define DA7219_M_BUTTON_B_PRESSED_MASK         (0x1 << 1)
+#define DA7219_M_BUTTON_C_PRESSED_SHIFT                2
+#define DA7219_M_BUTTON_C_PRESSED_MASK         (0x1 << 2)
+#define DA7219_M_BUTTON_D_PRESSED_SHIFT                3
+#define DA7219_M_BUTTON_D_PRESSED_MASK         (0x1 << 3)
+#define DA7219_M_BUTTON_D_RELEASED_SHIFT       4
+#define DA7219_M_BUTTON_D_RELEASED_MASK                (0x1 << 4)
+#define DA7219_M_BUTTON_C_RELEASED_SHIFT       5
+#define DA7219_M_BUTTON_C_RELEASED_MASK                (0x1 << 5)
+#define DA7219_M_BUTTON_B_RELEASED_SHIFT       6
+#define DA7219_M_BUTTON_B_RELEASED_MASK                (0x1 << 6)
+#define DA7219_M_BUTTON_A_RELEASED_SHIFT       7
+#define DA7219_M_BUTTON_A_RELEASED_MASK                (0x1 << 7)
+
+/* DA7219_ACCDET_CONFIG_1 = 0xC6 */
+#define DA7219_ACCDET_EN_SHIFT         0
+#define DA7219_ACCDET_EN_MASK          (0x1 << 0)
+#define DA7219_BUTTON_CONFIG_SHIFT     1
+#define DA7219_BUTTON_CONFIG_MASK      (0x7 << 1)
+#define DA7219_MIC_DET_THRESH_SHIFT    4
+#define DA7219_MIC_DET_THRESH_MASK     (0x3 << 4)
+#define DA7219_JACK_TYPE_DET_EN_SHIFT  6
+#define DA7219_JACK_TYPE_DET_EN_MASK   (0x1 << 6)
+#define DA7219_PIN_ORDER_DET_EN_SHIFT  7
+#define DA7219_PIN_ORDER_DET_EN_MASK   (0x1 << 7)
+
+/* DA7219_ACCDET_CONFIG_2 = 0xC7 */
+#define DA7219_ACCDET_PAUSE_SHIFT      0
+#define DA7219_ACCDET_PAUSE_MASK       (0x1 << 0)
+#define DA7219_JACKDET_DEBOUNCE_SHIFT  1
+#define DA7219_JACKDET_DEBOUNCE_MASK   (0x7 << 1)
+#define DA7219_JACK_DETECT_RATE_SHIFT  4
+#define DA7219_JACK_DETECT_RATE_MASK   (0x3 << 4)
+#define DA7219_JACKDET_REM_DEB_SHIFT   6
+#define DA7219_JACKDET_REM_DEB_MASK    (0x3 << 6)
+
+/* DA7219_ACCDET_CONFIG_3 = 0xC8 */
+#define DA7219_A_D_BUTTON_THRESH_SHIFT 0
+#define DA7219_A_D_BUTTON_THRESH_MASK  (0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_4 = 0xC9 */
+#define DA7219_D_B_BUTTON_THRESH_SHIFT 0
+#define DA7219_D_B_BUTTON_THRESH_MASK  (0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_5 = 0xCA */
+#define DA7219_B_C_BUTTON_THRESH_SHIFT 0
+#define DA7219_B_C_BUTTON_THRESH_MASK  (0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_6 = 0xCB */
+#define DA7219_C_MIC_BUTTON_THRESH_SHIFT       0
+#define DA7219_C_MIC_BUTTON_THRESH_MASK                (0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_7 = 0xCC */
+#define DA7219_BUTTON_AVERAGE_SHIFT    0
+#define DA7219_BUTTON_AVERAGE_MASK     (0x3 << 0)
+#define DA7219_ADC_1_BIT_REPEAT_SHIFT  2
+#define DA7219_ADC_1_BIT_REPEAT_MASK   (0x3 << 2)
+#define DA7219_PIN_ORDER_FORCE_SHIFT   4
+#define DA7219_PIN_ORDER_FORCE_MASK    (0x1 << 4)
+#define DA7219_JACK_TYPE_FORCE_SHIFT   5
+#define DA7219_JACK_TYPE_FORCE_MASK    (0x1 << 5)
+
+/* DA7219_ACCDET_CONFIG_8 = 0xCD */
+#define DA7219_HPTEST_EN_SHIFT         0
+#define DA7219_HPTEST_EN_MASK          (0x1 << 0)
+#define DA7219_HPTEST_RES_SEL_SHIFT    1
+#define DA7219_HPTEST_RES_SEL_MASK     (0x3 << 1)
+#define DA7219_HPTEST_RES_SEL_1KOHMS   (0x0 << 1)
+#define DA7219_HPTEST_COMP_SHIFT       4
+#define DA7219_HPTEST_COMP_MASK                (0x1 << 4)
+
+
+#define DA7219_AAD_MAX_BUTTONS         4
+#define DA7219_AAD_REPORT_ALL_MASK     (SND_JACK_MECHANICAL |                  \
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |  \
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |      \
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+#define DA7219_AAD_MICBIAS_CHK_DELAY   10
+#define DA7219_AAD_MICBIAS_CHK_RETRIES 5
+
+#define DA7219_AAD_HPTEST_RAMP_FREQ    0x28
+#define DA7219_AAD_HPTEST_PERIOD       65
+
+enum da7219_aad_event_regs {
+       DA7219_AAD_IRQ_REG_A = 0,
+       DA7219_AAD_IRQ_REG_B,
+       DA7219_AAD_IRQ_REG_MAX,
+};
+
+/* Private data */
+struct da7219_aad_priv {
+       struct snd_soc_codec *codec;
+       int irq;
+
+       u8 micbias_pulse_lvl;
+       u32 micbias_pulse_time;
+
+       u8 btn_cfg;
+
+       struct work_struct btn_det_work;
+       struct work_struct hptest_work;
+
+       struct snd_soc_jack *jack;
+       bool jack_inserted;
+};
+
+/* AAD control */
+void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+/* Init/Exit */
+int da7219_aad_init(struct snd_soc_codec *codec);
+void da7219_aad_exit(struct snd_soc_codec *codec);
+
+#endif /* __DA7219_AAD_H */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
new file mode 100644 (file)
index 0000000..f238c1e
--- /dev/null
@@ -0,0 +1,1955 @@
+/*
+ * da7219.c - DA7219 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7219.h>
+#include "da7219.h"
+#include "da7219-aad.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7219_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_adc_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_ana_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_sidetone_gain_tlv, -4200, 300, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_tonegen_gain_tlv, -4500, 300, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7219_dac_eq_band_tlv, -1050, 150, 0);
+
+static const DECLARE_TLV_DB_RANGE(da7219_dac_dig_gain_tlv,
+       0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+       /* -77.25dB to 12dB */
+       0x08, 0x7f, TLV_DB_SCALE_ITEM(-7725, 75, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(da7219_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_hp_gain_tlv, -5700, 100, 0);
+
+/* Input Enums */
+static const char * const da7219_alc_attack_rate_txt[] = {
+       "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+       "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+       "30024/fs"
+};
+
+static const struct soc_enum da7219_alc_attack_rate =
+       SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_ATTACK_SHIFT,
+                       DA7219_ALC_ATTACK_MAX, da7219_alc_attack_rate_txt);
+
+static const char * const da7219_alc_release_rate_txt[] = {
+       "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+       "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs"
+};
+
+static const struct soc_enum da7219_alc_release_rate =
+       SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_RELEASE_SHIFT,
+                       DA7219_ALC_RELEASE_MAX, da7219_alc_release_rate_txt);
+
+static const char * const da7219_alc_hold_time_txt[] = {
+       "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+       "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+       "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7219_alc_hold_time =
+       SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_HOLD_SHIFT,
+                       DA7219_ALC_HOLD_MAX, da7219_alc_hold_time_txt);
+
+static const char * const da7219_alc_env_rate_txt[] = {
+       "1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7219_alc_env_attack_rate =
+       SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_ATTACK_SHIFT,
+                       DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt);
+
+static const struct soc_enum da7219_alc_env_release_rate =
+       SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_RELEASE_SHIFT,
+                       DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt);
+
+static const char * const da7219_alc_anticlip_step_txt[] = {
+       "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs"
+};
+
+static const struct soc_enum da7219_alc_anticlip_step =
+       SOC_ENUM_SINGLE(DA7219_ALC_ANTICLIP_CTRL,
+                       DA7219_ALC_ANTICLIP_STEP_SHIFT,
+                       DA7219_ALC_ANTICLIP_STEP_MAX,
+                       da7219_alc_anticlip_step_txt);
+
+/* Input/Output Enums */
+static const char * const da7219_gain_ramp_rate_txt[] = {
+       "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+       "Nominal Rate / 16"
+};
+
+static const struct soc_enum da7219_gain_ramp_rate =
+       SOC_ENUM_SINGLE(DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_SHIFT,
+                       DA7219_GAIN_RAMP_RATE_MAX, da7219_gain_ramp_rate_txt);
+
+static const char * const da7219_hpf_mode_txt[] = {
+       "Disabled", "Audio", "Voice"
+};
+
+static const unsigned int da7219_hpf_mode_val[] = {
+       DA7219_HPF_DISABLED, DA7219_HPF_AUDIO_EN, DA7219_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7219_adc_hpf_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7219_ADC_FILTERS1, DA7219_HPF_MODE_SHIFT,
+                             DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX,
+                             da7219_hpf_mode_txt, da7219_hpf_mode_val);
+
+static const struct soc_enum da7219_dac_hpf_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7219_DAC_FILTERS1, DA7219_HPF_MODE_SHIFT,
+                             DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX,
+                             da7219_hpf_mode_txt, da7219_hpf_mode_val);
+
+static const char * const da7219_audio_hpf_corner_txt[] = {
+       "2Hz", "4Hz", "8Hz", "16Hz"
+};
+
+static const struct soc_enum da7219_adc_audio_hpf_corner =
+       SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1,
+                       DA7219_ADC_AUDIO_HPF_CORNER_SHIFT,
+                       DA7219_AUDIO_HPF_CORNER_MAX,
+                       da7219_audio_hpf_corner_txt);
+
+static const struct soc_enum da7219_dac_audio_hpf_corner =
+       SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1,
+                       DA7219_DAC_AUDIO_HPF_CORNER_SHIFT,
+                       DA7219_AUDIO_HPF_CORNER_MAX,
+                       da7219_audio_hpf_corner_txt);
+
+static const char * const da7219_voice_hpf_corner_txt[] = {
+       "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da7219_adc_voice_hpf_corner =
+       SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1,
+                       DA7219_ADC_VOICE_HPF_CORNER_SHIFT,
+                       DA7219_VOICE_HPF_CORNER_MAX,
+                       da7219_voice_hpf_corner_txt);
+
+static const struct soc_enum da7219_dac_voice_hpf_corner =
+       SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1,
+                       DA7219_DAC_VOICE_HPF_CORNER_SHIFT,
+                       DA7219_VOICE_HPF_CORNER_MAX,
+                       da7219_voice_hpf_corner_txt);
+
+static const char * const da7219_tonegen_dtmf_key_txt[] = {
+       "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+       "*", "#"
+};
+
+static const struct soc_enum da7219_tonegen_dtmf_key =
+       SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG1, DA7219_DTMF_REG_SHIFT,
+                       DA7219_DTMF_REG_MAX, da7219_tonegen_dtmf_key_txt);
+
+static const char * const da7219_tonegen_swg_sel_txt[] = {
+       "Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7219_tonegen_swg_sel =
+       SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG2, DA7219_SWG_SEL_SHIFT,
+                       DA7219_SWG_SEL_MAX, da7219_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7219_dac_softmute_rate_txt[] = {
+       "1 Sample", "2 Samples", "4 Samples", "8 Samples", "16 Samples",
+       "32 Samples", "64 Samples"
+};
+
+static const struct soc_enum da7219_dac_softmute_rate =
+       SOC_ENUM_SINGLE(DA7219_DAC_FILTERS5, DA7219_DAC_SOFTMUTE_RATE_SHIFT,
+                       DA7219_DAC_SOFTMUTE_RATE_MAX,
+                       da7219_dac_softmute_rate_txt);
+
+static const char * const da7219_dac_ng_setup_time_txt[] = {
+       "256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7219_dac_ng_setup_time =
+       SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+                       DA7219_DAC_NG_SETUP_TIME_SHIFT,
+                       DA7219_DAC_NG_SETUP_TIME_MAX,
+                       da7219_dac_ng_setup_time_txt);
+
+static const char * const da7219_dac_ng_rampup_txt[] = {
+       "0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7219_dac_ng_rampup_rate =
+       SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+                       DA7219_DAC_NG_RAMPUP_RATE_SHIFT,
+                       DA7219_DAC_NG_RAMP_RATE_MAX,
+                       da7219_dac_ng_rampup_txt);
+
+static const char * const da7219_dac_ng_rampdown_txt[] = {
+       "0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7219_dac_ng_rampdown_rate =
+       SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+                       DA7219_DAC_NG_RAMPDN_RATE_SHIFT,
+                       DA7219_DAC_NG_RAMP_RATE_MAX,
+                       da7219_dac_ng_rampdown_txt);
+
+
+static const char * const da7219_cp_track_mode_txt[] = {
+       "Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7219_cp_track_mode_val[] = {
+       DA7219_CP_MCHANGE_LARGEST_VOL, DA7219_CP_MCHANGE_DAC_VOL,
+       DA7219_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7219_cp_track_mode =
+       SOC_VALUE_ENUM_SINGLE(DA7219_CP_CTRL, DA7219_CP_MCHANGE_SHIFT,
+                             DA7219_CP_MCHANGE_REL_MASK, DA7219_CP_MCHANGE_MAX,
+                             da7219_cp_track_mode_txt,
+                             da7219_cp_track_mode_val);
+
+
+/*
+ * Control Functions
+ */
+
+/* Locked Kcontrol calls */
+static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mutex_lock(&da7219->lock);
+       ret = snd_soc_get_volsw(kcontrol, ucontrol);
+       mutex_unlock(&da7219->lock);
+
+       return ret;
+}
+
+static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mutex_lock(&da7219->lock);
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       mutex_unlock(&da7219->lock);
+
+       return ret;
+}
+
+static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mutex_lock(&da7219->lock);
+       ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+       mutex_unlock(&da7219->lock);
+
+       return ret;
+}
+
+static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mutex_lock(&da7219->lock);
+       ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+       mutex_unlock(&da7219->lock);
+
+       return ret;
+}
+
+/* ALC */
+static void da7219_alc_calib(struct snd_soc_codec *codec)
+{
+       u8 mic_ctrl, mixin_ctrl, adc_ctrl, calib_ctrl;
+
+       /* Save current state of mic control register */
+       mic_ctrl = snd_soc_read(codec, DA7219_MIC_1_CTRL);
+
+       /* Save current state of input mixer control register */
+       mixin_ctrl = snd_soc_read(codec, DA7219_MIXIN_L_CTRL);
+
+       /* Save current state of input ADC control register */
+       adc_ctrl = snd_soc_read(codec, DA7219_ADC_L_CTRL);
+
+       /* Enable then Mute MIC PGAs */
+       snd_soc_update_bits(codec, DA7219_MIC_1_CTRL, DA7219_MIC_1_AMP_EN_MASK,
+                           DA7219_MIC_1_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_MIC_1_CTRL,
+                           DA7219_MIC_1_AMP_MUTE_EN_MASK,
+                           DA7219_MIC_1_AMP_MUTE_EN_MASK);
+
+       /* Enable input mixers unmuted */
+       snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL,
+                           DA7219_MIXIN_L_AMP_EN_MASK |
+                           DA7219_MIXIN_L_AMP_MUTE_EN_MASK,
+                           DA7219_MIXIN_L_AMP_EN_MASK);
+
+       /* Enable input filters unmuted */
+       snd_soc_update_bits(codec, DA7219_ADC_L_CTRL,
+                           DA7219_ADC_L_MUTE_EN_MASK | DA7219_ADC_L_EN_MASK,
+                           DA7219_ADC_L_EN_MASK);
+
+       /* Perform auto calibration */
+       snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+                           DA7219_ALC_AUTO_CALIB_EN_MASK,
+                           DA7219_ALC_AUTO_CALIB_EN_MASK);
+       do {
+               calib_ctrl = snd_soc_read(codec, DA7219_ALC_CTRL1);
+       } while (calib_ctrl & DA7219_ALC_AUTO_CALIB_EN_MASK);
+
+       /* If auto calibration fails, disable DC offset, hybrid ALC */
+       if (calib_ctrl & DA7219_ALC_CALIB_OVERFLOW_MASK) {
+               dev_warn(codec->dev,
+                        "ALC auto calibration failed with overflow\n");
+               snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+                                   DA7219_ALC_OFFSET_EN_MASK |
+                                   DA7219_ALC_SYNC_MODE_MASK, 0);
+       } else {
+               /* Enable DC offset cancellation, hybrid mode */
+               snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+                                   DA7219_ALC_OFFSET_EN_MASK |
+                                   DA7219_ALC_SYNC_MODE_MASK,
+                                   DA7219_ALC_OFFSET_EN_MASK |
+                                   DA7219_ALC_SYNC_MODE_MASK);
+       }
+
+       /* Restore input filter control register to original state */
+       snd_soc_write(codec, DA7219_ADC_L_CTRL, adc_ctrl);
+
+       /* Restore input mixer control registers to original state */
+       snd_soc_write(codec, DA7219_MIXIN_L_CTRL, mixin_ctrl);
+
+       /* Restore MIC control registers to original states */
+       snd_soc_write(codec, DA7219_MIC_1_CTRL, mic_ctrl);
+}
+
+static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       /*
+        * If ALC in operation and value of control has been updated,
+        * make sure calibrated offsets are updated.
+        */
+       if ((ret == 1) && (da7219->alc_en))
+               da7219_alc_calib(codec);
+
+       return ret;
+}
+
+static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+
+       /* Force ALC offset calibration if enabling ALC */
+       if ((ucontrol->value.integer.value[0]) && (!da7219->alc_en)) {
+               da7219_alc_calib(codec);
+               da7219->alc_en = true;
+       } else {
+               da7219->alc_en = false;
+       }
+
+       return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int reg = mixer_ctrl->reg;
+       u16 val;
+       int ret;
+
+       mutex_lock(&da7219->lock);
+       ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
+       mutex_unlock(&da7219->lock);
+
+       if (ret)
+               return ret;
+
+       /*
+        * Frequency value spans two 8-bit registers, lower then upper byte.
+        * Therefore we need to convert to host endianness here.
+        */
+       ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+       return 0;
+}
+
+static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct soc_mixer_control *mixer_ctrl =
+               (struct soc_mixer_control *) kcontrol->private_value;
+       unsigned int reg = mixer_ctrl->reg;
+       u16 val;
+       int ret;
+
+       /*
+        * Frequency value spans two 8-bit registers, lower then upper byte.
+        * Therefore we need to convert to little endian here to align with
+        * HW registers.
+        */
+       val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+       mutex_lock(&da7219->lock);
+       ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val));
+       mutex_unlock(&da7219->lock);
+
+       return ret;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7219_snd_controls[] = {
+       /* Mics */
+       SOC_SINGLE_TLV("Mic Volume", DA7219_MIC_1_GAIN,
+                      DA7219_MIC_1_AMP_GAIN_SHIFT, DA7219_MIC_1_AMP_GAIN_MAX,
+                      DA7219_NO_INVERT, da7219_mic_gain_tlv),
+       SOC_SINGLE("Mic Switch", DA7219_MIC_1_CTRL,
+                  DA7219_MIC_1_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_INVERT),
+
+       /* Mixer Input */
+       SOC_SINGLE_EXT_TLV("Mixin Volume", DA7219_MIXIN_L_GAIN,
+                          DA7219_MIXIN_L_AMP_GAIN_SHIFT,
+                          DA7219_MIXIN_L_AMP_GAIN_MAX, DA7219_NO_INVERT,
+                          snd_soc_get_volsw, da7219_mixin_gain_put,
+                          da7219_mixin_gain_tlv),
+       SOC_SINGLE("Mixin Switch", DA7219_MIXIN_L_CTRL,
+                  DA7219_MIXIN_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_INVERT),
+       SOC_SINGLE("Mixin Gain Ramp Switch", DA7219_MIXIN_L_CTRL,
+                  DA7219_MIXIN_L_AMP_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_NO_INVERT),
+       SOC_SINGLE("Mixin ZC Gain Switch", DA7219_MIXIN_L_CTRL,
+                  DA7219_MIXIN_L_AMP_ZC_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_NO_INVERT),
+
+       /* ADC */
+       SOC_SINGLE_TLV("Capture Digital Volume", DA7219_ADC_L_GAIN,
+                      DA7219_ADC_L_DIGITAL_GAIN_SHIFT,
+                      DA7219_ADC_L_DIGITAL_GAIN_MAX, DA7219_NO_INVERT,
+                      da7219_adc_dig_gain_tlv),
+       SOC_SINGLE("Capture Digital Switch", DA7219_ADC_L_CTRL,
+                  DA7219_ADC_L_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_INVERT),
+       SOC_SINGLE("Capture Digital Gain Ramp Switch", DA7219_ADC_L_CTRL,
+                  DA7219_ADC_L_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_NO_INVERT),
+
+       /* ALC */
+       SOC_ENUM("ALC Attack Rate", da7219_alc_attack_rate),
+       SOC_ENUM("ALC Release Rate", da7219_alc_release_rate),
+       SOC_ENUM("ALC Hold Time", da7219_alc_hold_time),
+       SOC_ENUM("ALC Envelope Attack Rate", da7219_alc_env_attack_rate),
+       SOC_ENUM("ALC Envelope Release Rate", da7219_alc_env_release_rate),
+       SOC_SINGLE_TLV("ALC Noise Threshold", DA7219_ALC_NOISE,
+                      DA7219_ALC_NOISE_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+                      DA7219_INVERT, da7219_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Min Threshold", DA7219_ALC_TARGET_MIN,
+                      DA7219_ALC_THRESHOLD_MIN_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+                      DA7219_INVERT, da7219_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Threshold", DA7219_ALC_TARGET_MAX,
+                      DA7219_ALC_THRESHOLD_MAX_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+                      DA7219_INVERT, da7219_alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Attenuation", DA7219_ALC_GAIN_LIMITS,
+                      DA7219_ALC_ATTEN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX,
+                      DA7219_NO_INVERT, da7219_alc_gain_tlv),
+       SOC_SINGLE_TLV("ALC Max Volume", DA7219_ALC_GAIN_LIMITS,
+                      DA7219_ALC_GAIN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX,
+                      DA7219_NO_INVERT, da7219_alc_gain_tlv),
+       SOC_SINGLE_RANGE_TLV("ALC Min Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS,
+                            DA7219_ALC_ANA_GAIN_MIN_SHIFT,
+                            DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX,
+                            DA7219_NO_INVERT, da7219_alc_ana_gain_tlv),
+       SOC_SINGLE_RANGE_TLV("ALC Max Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS,
+                            DA7219_ALC_ANA_GAIN_MAX_SHIFT,
+                            DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX,
+                            DA7219_NO_INVERT, da7219_alc_ana_gain_tlv),
+       SOC_ENUM("ALC Anticlip Step", da7219_alc_anticlip_step),
+       SOC_SINGLE("ALC Anticlip Switch", DA7219_ALC_ANTICLIP_CTRL,
+                  DA7219_ALC_ANTIPCLIP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_NO_INVERT),
+       SOC_SINGLE_EXT("ALC Switch", DA7219_ALC_CTRL1, DA7219_ALC_EN_SHIFT,
+                      DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT,
+                      snd_soc_get_volsw, da7219_alc_sw_put),
+
+       /* Input High-Pass Filters */
+       SOC_ENUM("ADC HPF Mode", da7219_adc_hpf_mode),
+       SOC_ENUM("ADC HPF Corner Audio", da7219_adc_audio_hpf_corner),
+       SOC_ENUM("ADC HPF Corner Voice", da7219_adc_voice_hpf_corner),
+
+       /* Sidetone Filter */
+       SOC_SINGLE_TLV("Sidetone Volume", DA7219_SIDETONE_GAIN,
+                      DA7219_SIDETONE_GAIN_SHIFT, DA7219_SIDETONE_GAIN_MAX,
+                      DA7219_NO_INVERT, da7219_sidetone_gain_tlv),
+       SOC_SINGLE("Sidetone Switch", DA7219_SIDETONE_CTRL,
+                  DA7219_SIDETONE_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                  DA7219_INVERT),
+
+       /* Tone Generator */
+       SOC_SINGLE_EXT_TLV("ToneGen Volume", DA7219_TONE_GEN_CFG2,
+                          DA7219_TONE_GEN_GAIN_SHIFT, DA7219_TONE_GEN_GAIN_MAX,
+                          DA7219_NO_INVERT, da7219_volsw_locked_get,
+                          da7219_volsw_locked_put, da7219_tonegen_gain_tlv),
+       SOC_ENUM_EXT("ToneGen DTMF Key", da7219_tonegen_dtmf_key,
+                    da7219_enum_locked_get, da7219_enum_locked_put),
+       SOC_SINGLE_EXT("ToneGen DTMF Switch", DA7219_TONE_GEN_CFG1,
+                      DA7219_DTMF_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                      DA7219_NO_INVERT, da7219_volsw_locked_get,
+                      da7219_volsw_locked_put),
+       SOC_ENUM_EXT("ToneGen Sinewave Gen Type", da7219_tonegen_swg_sel,
+                    da7219_enum_locked_get, da7219_enum_locked_put),
+       SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7219_TONE_GEN_FREQ1_L,
+                      DA7219_FREQ1_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT,
+                      da7219_tonegen_freq_get, da7219_tonegen_freq_put),
+       SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7219_TONE_GEN_FREQ2_L,
+                      DA7219_FREQ2_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT,
+                      da7219_tonegen_freq_get, da7219_tonegen_freq_put),
+       SOC_SINGLE_EXT("ToneGen On Time", DA7219_TONE_GEN_ON_PER,
+                      DA7219_BEEP_ON_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX,
+                      DA7219_NO_INVERT, da7219_volsw_locked_get,
+                      da7219_volsw_locked_put),
+       SOC_SINGLE("ToneGen Off Time", DA7219_TONE_GEN_OFF_PER,
+                  DA7219_BEEP_OFF_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX,
+                  DA7219_NO_INVERT),
+
+       /* Gain ramping */
+       SOC_ENUM("Gain Ramp Rate", da7219_gain_ramp_rate),
+
+       /* DAC High-Pass Filter */
+       SOC_ENUM_EXT("DAC HPF Mode", da7219_dac_hpf_mode,
+                    da7219_enum_locked_get, da7219_enum_locked_put),
+       SOC_ENUM("DAC HPF Corner Audio", da7219_dac_audio_hpf_corner),
+       SOC_ENUM("DAC HPF Corner Voice", da7219_dac_voice_hpf_corner),
+
+       /* DAC 5-Band Equaliser */
+       SOC_SINGLE_TLV("DAC EQ Band1 Volume", DA7219_DAC_FILTERS2,
+                      DA7219_DAC_EQ_BAND1_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+                      DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+       SOC_SINGLE_TLV("DAC EQ Band2 Volume", DA7219_DAC_FILTERS2,
+                      DA7219_DAC_EQ_BAND2_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+                      DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+       SOC_SINGLE_TLV("DAC EQ Band3 Volume", DA7219_DAC_FILTERS3,
+                      DA7219_DAC_EQ_BAND3_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+                      DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+       SOC_SINGLE_TLV("DAC EQ Band4 Volume", DA7219_DAC_FILTERS3,
+                      DA7219_DAC_EQ_BAND4_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+                      DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+       SOC_SINGLE_TLV("DAC EQ Band5 Volume", DA7219_DAC_FILTERS4,
+                      DA7219_DAC_EQ_BAND5_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+                      DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+       SOC_SINGLE_EXT("DAC EQ Switch", DA7219_DAC_FILTERS4,
+                      DA7219_DAC_EQ_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                      DA7219_NO_INVERT, da7219_volsw_locked_get,
+                      da7219_volsw_locked_put),
+
+       /* DAC Softmute */
+       SOC_ENUM("DAC Soft Mute Rate", da7219_dac_softmute_rate),
+       SOC_SINGLE_EXT("DAC Soft Mute Switch", DA7219_DAC_FILTERS5,
+                      DA7219_DAC_SOFTMUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                      DA7219_NO_INVERT, da7219_volsw_locked_get,
+                      da7219_volsw_locked_put),
+
+       /* DAC Noise Gate */
+       SOC_ENUM("DAC NG Setup Time", da7219_dac_ng_setup_time),
+       SOC_ENUM("DAC NG Rampup Rate", da7219_dac_ng_rampup_rate),
+       SOC_ENUM("DAC NG Rampdown Rate", da7219_dac_ng_rampdown_rate),
+       SOC_SINGLE_TLV("DAC NG Off Threshold", DA7219_DAC_NG_OFF_THRESH,
+                      DA7219_DAC_NG_OFF_THRESHOLD_SHIFT,
+                      DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT,
+                      da7219_dac_ng_threshold_tlv),
+       SOC_SINGLE_TLV("DAC NG On Threshold", DA7219_DAC_NG_ON_THRESH,
+                      DA7219_DAC_NG_ON_THRESHOLD_SHIFT,
+                      DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT,
+                      da7219_dac_ng_threshold_tlv),
+       SOC_SINGLE("DAC NG Switch", DA7219_DAC_NG_CTRL, DA7219_DAC_NG_EN_SHIFT,
+                  DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+
+       /* DACs */
+       SOC_DOUBLE_R_EXT_TLV("Playback Digital Volume", DA7219_DAC_L_GAIN,
+                            DA7219_DAC_R_GAIN, DA7219_DAC_L_DIGITAL_GAIN_SHIFT,
+                            DA7219_DAC_DIGITAL_GAIN_MAX, DA7219_NO_INVERT,
+                            da7219_volsw_locked_get, da7219_volsw_locked_put,
+                            da7219_dac_dig_gain_tlv),
+       SOC_DOUBLE_R_EXT("Playback Digital Switch", DA7219_DAC_L_CTRL,
+                        DA7219_DAC_R_CTRL, DA7219_DAC_L_MUTE_EN_SHIFT,
+                        DA7219_SWITCH_EN_MAX, DA7219_INVERT,
+                        da7219_volsw_locked_get, da7219_volsw_locked_put),
+       SOC_DOUBLE_R("Playback Digital Gain Ramp Switch", DA7219_DAC_L_CTRL,
+                    DA7219_DAC_R_CTRL, DA7219_DAC_L_RAMP_EN_SHIFT,
+                    DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+
+       /* CP */
+       SOC_ENUM("Charge Pump Track Mode", da7219_cp_track_mode),
+       SOC_SINGLE("Charge Pump Threshold", DA7219_CP_VOL_THRESHOLD1,
+                  DA7219_CP_THRESH_VDD2_SHIFT, DA7219_CP_THRESH_VDD2_MAX,
+                  DA7219_NO_INVERT),
+
+       /* Headphones */
+       SOC_DOUBLE_R_EXT_TLV("Headphone Volume", DA7219_HP_L_GAIN,
+                            DA7219_HP_R_GAIN, DA7219_HP_L_AMP_GAIN_SHIFT,
+                            DA7219_HP_AMP_GAIN_MAX, DA7219_NO_INVERT,
+                            da7219_volsw_locked_get, da7219_volsw_locked_put,
+                            da7219_hp_gain_tlv),
+       SOC_DOUBLE_R_EXT("Headphone Switch", DA7219_HP_L_CTRL, DA7219_HP_R_CTRL,
+                        DA7219_HP_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+                        DA7219_INVERT, da7219_volsw_locked_get,
+                        da7219_volsw_locked_put),
+       SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7219_HP_L_CTRL,
+                    DA7219_HP_R_CTRL, DA7219_HP_L_AMP_RAMP_EN_SHIFT,
+                    DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+       SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7219_HP_L_CTRL,
+                    DA7219_HP_R_CTRL, DA7219_HP_L_AMP_ZC_EN_SHIFT,
+                    DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7219_out_sel_txt[] = {
+       "ADC", "Tone Generator", "DAIL", "DAIR"
+};
+
+static const struct soc_enum da7219_out_dail_sel =
+       SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI,
+                       DA7219_DAI_L_SRC_SHIFT,
+                       DA7219_OUT_SRC_MAX,
+                       da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dail_sel_mux =
+       SOC_DAPM_ENUM("Out DAIL Mux", da7219_out_dail_sel);
+
+static const struct soc_enum da7219_out_dair_sel =
+       SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI,
+                       DA7219_DAI_R_SRC_SHIFT,
+                       DA7219_OUT_SRC_MAX,
+                       da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dair_sel_mux =
+       SOC_DAPM_ENUM("Out DAIR Mux", da7219_out_dair_sel);
+
+static const struct soc_enum da7219_out_dacl_sel =
+       SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC,
+                       DA7219_DAC_L_SRC_SHIFT,
+                       DA7219_OUT_SRC_MAX,
+                       da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dacl_sel_mux =
+       SOC_DAPM_ENUM("Out DACL Mux", da7219_out_dacl_sel);
+
+static const struct soc_enum da7219_out_dacr_sel =
+       SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC,
+                       DA7219_DAC_R_SRC_SHIFT,
+                       DA7219_OUT_SRC_MAX,
+                       da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dacr_sel_mux =
+       SOC_DAPM_ENUM("Out DACR Mux", da7219_out_dacr_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+static const struct snd_kcontrol_new da7219_mixin_controls[] = {
+       SOC_DAPM_SINGLE("Mic Switch", DA7219_MIXIN_L_SELECT,
+                       DA7219_MIXIN_L_MIX_SELECT_SHIFT,
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+static const struct snd_kcontrol_new da7219_mixout_l_controls[] = {
+       SOC_DAPM_SINGLE("DACL Switch", DA7219_MIXOUT_L_SELECT,
+                       DA7219_MIXOUT_L_MIX_SELECT_SHIFT,
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+static const struct snd_kcontrol_new da7219_mixout_r_controls[] = {
+       SOC_DAPM_SINGLE("DACR Switch", DA7219_MIXOUT_R_SELECT,
+                       DA7219_MIXOUT_R_MIX_SELECT_SHIFT,
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+#define DA7219_DMIX_ST_CTRLS(reg)                                      \
+       SOC_DAPM_SINGLE("Out FilterL Switch", reg,                      \
+                       DA7219_DMIX_ST_SRC_OUTFILT1L_SHIFT,             \
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),        \
+       SOC_DAPM_SINGLE("Out FilterR Switch", reg,                      \
+                       DA7219_DMIX_ST_SRC_OUTFILT1R_SHIFT,             \
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),        \
+       SOC_DAPM_SINGLE("Sidetone Switch", reg,                         \
+                       DA7219_DMIX_ST_SRC_SIDETONE_SHIFT,              \
+                       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT)         \
+
+static const struct snd_kcontrol_new da7219_st_out_filtl_mix_controls[] = {
+       DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
+       DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+static int da7219_dai_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       u8 pll_ctrl, pll_status;
+       int i = 0;
+       bool srm_lock = false;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (da7219->master)
+                       /* Enable DAI clks for master mode */
+                       snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+                                           DA7219_DAI_CLK_EN_MASK,
+                                           DA7219_DAI_CLK_EN_MASK);
+
+               /* PC synchronised to DAI */
+               snd_soc_update_bits(codec, DA7219_PC_COUNT,
+                                   DA7219_PC_FREERUN_MASK, 0);
+
+               /* Slave mode, if SRM not enabled no need for status checks */
+               pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL);
+               if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
+                       return 0;
+
+               /* Check SRM has locked */
+               do {
+                       pll_status = snd_soc_read(codec, DA7219_PLL_SRM_STS);
+                       if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
+                               srm_lock = true;
+                       } else {
+                               ++i;
+                               msleep(50);
+                       }
+               } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
+
+               if (!srm_lock)
+                       dev_warn(codec->dev, "SRM failed to lock\n");
+
+               return 0;
+       case SND_SOC_DAPM_POST_PMD:
+               /* PC free-running */
+               snd_soc_update_bits(codec, DA7219_PC_COUNT,
+                                   DA7219_PC_FREERUN_MASK,
+                                   DA7219_PC_FREERUN_MASK);
+
+               /* Disable DAI clks if in master mode */
+               if (da7219->master)
+                       snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+                                           DA7219_DAI_CLK_EN_MASK, 0);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
+       /* Input Supplies */
+       SND_SOC_DAPM_SUPPLY("Mic Bias", DA7219_MICBIAS_CTRL,
+                           DA7219_MICBIAS1_EN_SHIFT, DA7219_NO_INVERT,
+                           NULL, 0),
+
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("MIC"),
+
+       /* Input PGAs */
+       SND_SOC_DAPM_PGA("Mic PGA", DA7219_MIC_1_CTRL,
+                        DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mixin PGA", DA7219_MIXIN_L_CTRL,
+                        DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                        NULL, 0),
+
+       /* Input Filters */
+       SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT,
+                        DA7219_NO_INVERT),
+
+       /* Tone Generator */
+       SND_SOC_DAPM_SIGGEN("TONE"),
+       SND_SOC_DAPM_PGA("Tone Generator", DA7219_TONE_GEN_CFG1,
+                        DA7219_START_STOPN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+
+       /* Sidetone Input */
+       SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7219_SIDETONE_CTRL,
+                        DA7219_SIDETONE_EN_SHIFT, DA7219_NO_INVERT),
+
+       /* Input Mixer Supply */
+       SND_SOC_DAPM_SUPPLY("Mixer In Supply", DA7219_MIXIN_L_CTRL,
+                           DA7219_MIXIN_L_MIX_EN_SHIFT, DA7219_NO_INVERT,
+                           NULL, 0),
+
+       /* Input Mixer */
+       SND_SOC_DAPM_MIXER("Mixer In", SND_SOC_NOPM, 0, 0,
+                          da7219_mixin_controls,
+                          ARRAY_SIZE(da7219_mixin_controls)),
+
+       /* Input Muxes */
+       SND_SOC_DAPM_MUX("Out DAIL Mux", SND_SOC_NOPM, 0, 0,
+                        &da7219_out_dail_sel_mux),
+       SND_SOC_DAPM_MUX("Out DAIR Mux", SND_SOC_NOPM, 0, 0,
+                        &da7219_out_dair_sel_mux),
+
+       /* DAI Supply */
+       SND_SOC_DAPM_SUPPLY("DAI", DA7219_DAI_CTRL, DA7219_DAI_EN_SHIFT,
+                           DA7219_NO_INVERT, da7219_dai_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* DAI */
+       SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Output Muxes */
+       SND_SOC_DAPM_MUX("Out DACL Mux", SND_SOC_NOPM, 0, 0,
+                        &da7219_out_dacl_sel_mux),
+       SND_SOC_DAPM_MUX("Out DACR Mux", SND_SOC_NOPM, 0, 0,
+                        &da7219_out_dacr_sel_mux),
+
+       /* Output Mixers */
+       SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+                          da7219_mixout_l_controls,
+                          ARRAY_SIZE(da7219_mixout_l_controls)),
+       SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+                          da7219_mixout_r_controls,
+                          ARRAY_SIZE(da7219_mixout_r_controls)),
+
+       /* Sidetone Mixers */
+       SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+                          da7219_st_out_filtl_mix_controls,
+                          ARRAY_SIZE(da7219_st_out_filtl_mix_controls)),
+       SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0,
+                          0, da7219_st_out_filtr_mix_controls,
+                          ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT,
+                        DA7219_NO_INVERT),
+       SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT,
+                        DA7219_NO_INVERT),
+
+       /* Output PGAs */
+       SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
+                        DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
+                        DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                        NULL, 0),
+       SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL,
+                        DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL,
+                        DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+
+       /* Output Supplies */
+       SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT,
+                           DA7219_NO_INVERT, NULL, 0),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+
+/*
+ * DAPM Mux Routes
+ */
+
+#define DA7219_OUT_DAI_MUX_ROUTES(name)                        \
+       {name, "ADC", "Mixer In"},                      \
+       {name, "Tone Generator", "Tone Generator"},     \
+       {name, "DAIL", "DAIOUT"},                       \
+       {name, "DAIR", "DAIOUT"}
+
+#define DA7219_OUT_DAC_MUX_ROUTES(name)                        \
+       {name, "ADC", "Mixer In"},                      \
+       {name, "Tone Generator", "Tone Generator"},             \
+       {name, "DAIL", "DAIIN"},                        \
+       {name, "DAIR", "DAIIN"}
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7219_DMIX_ST_ROUTES(name)                            \
+       {name, "Out FilterL Switch", "Mixer Out FilterL"},      \
+       {name, "Out FilterR Switch", "Mixer Out FilterR"},      \
+       {name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7219_audio_map[] = {
+       /* Input paths */
+       {"MIC", NULL, "Mic Bias"},
+       {"Mic PGA", NULL, "MIC"},
+       {"Mixin PGA", NULL, "Mic PGA"},
+       {"ADC", NULL, "Mixin PGA"},
+
+       {"Sidetone Filter", NULL, "ADC"},
+       {"Mixer In", NULL, "Mixer In Supply"},
+       {"Mixer In", "Mic Switch", "ADC"},
+
+       {"Tone Generator", NULL, "TONE"},
+
+       DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"),
+       DA7219_OUT_DAI_MUX_ROUTES("Out DAIR Mux"),
+
+       {"DAIOUT", NULL, "Out DAIL Mux"},
+       {"DAIOUT", NULL, "Out DAIR Mux"},
+       {"DAIOUT", NULL, "DAI"},
+
+       /* Output paths */
+       {"DAIIN", NULL, "DAI"},
+
+       DA7219_OUT_DAC_MUX_ROUTES("Out DACL Mux"),
+       DA7219_OUT_DAC_MUX_ROUTES("Out DACR Mux"),
+
+       {"Mixer Out FilterL", "DACL Switch", "Out DACL Mux"},
+       {"Mixer Out FilterR", "DACR Switch", "Out DACR Mux"},
+
+       DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+       DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+       {"DACL", NULL, "ST Mixer Out FilterL"},
+       {"DACR", NULL, "ST Mixer Out FilterR"},
+
+       {"Mixout Left PGA", NULL, "DACL"},
+       {"Mixout Right PGA", NULL, "DACR"},
+
+       {"Headphone Left PGA", NULL, "Mixout Left PGA"},
+       {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+
+       {"HPL", NULL, "Headphone Left PGA"},
+       {"HPR", NULL, "Headphone Right PGA"},
+
+       {"HPL", NULL, "Charge Pump"},
+       {"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq))
+               return 0;
+
+       if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+               dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+                       freq);
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case DA7219_CLKSRC_MCLK_SQR:
+               snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+                                   DA7219_PLL_MCLK_SQR_EN_MASK,
+                                   DA7219_PLL_MCLK_SQR_EN_MASK);
+               break;
+       case DA7219_CLKSRC_MCLK:
+               snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+                                   DA7219_PLL_MCLK_SQR_EN_MASK, 0);
+               break;
+       default:
+               dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       da7219->clk_src = clk_id;
+
+       if (da7219->mclk) {
+               freq = clk_round_rate(da7219->mclk, freq);
+               ret = clk_set_rate(da7219->mclk, freq);
+               if (ret) {
+                       dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+                               freq);
+                       return ret;
+               }
+       }
+
+       da7219->mclk_rate = freq;
+
+       return 0;
+}
+
+static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+                             int source, unsigned int fref, unsigned int fout)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       u8 pll_ctrl, indiv_bits, indiv;
+       u8 pll_frac_top, pll_frac_bot, pll_integer;
+       u32 freq_ref;
+       u64 frac_div;
+
+       /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
+       if (da7219->mclk_rate == 32768) {
+               indiv_bits = DA7219_PLL_INDIV_2_5_MHZ;
+               indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL;
+       } else if (da7219->mclk_rate < 2000000) {
+               dev_err(codec->dev, "PLL input clock %d below valid range\n",
+                       da7219->mclk_rate);
+               return -EINVAL;
+       } else if (da7219->mclk_rate <= 5000000) {
+               indiv_bits = DA7219_PLL_INDIV_2_5_MHZ;
+               indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL;
+       } else if (da7219->mclk_rate <= 10000000) {
+               indiv_bits = DA7219_PLL_INDIV_5_10_MHZ;
+               indiv = DA7219_PLL_INDIV_5_10_MHZ_VAL;
+       } else if (da7219->mclk_rate <= 20000000) {
+               indiv_bits = DA7219_PLL_INDIV_10_20_MHZ;
+               indiv = DA7219_PLL_INDIV_10_20_MHZ_VAL;
+       } else if (da7219->mclk_rate <= 40000000) {
+               indiv_bits = DA7219_PLL_INDIV_20_40_MHZ;
+               indiv = DA7219_PLL_INDIV_20_40_MHZ_VAL;
+       } else if (da7219->mclk_rate <= 54000000) {
+               indiv_bits = DA7219_PLL_INDIV_40_54_MHZ;
+               indiv = DA7219_PLL_INDIV_40_54_MHZ_VAL;
+       } else {
+               dev_err(codec->dev, "PLL input clock %d above valid range\n",
+                       da7219->mclk_rate);
+               return -EINVAL;
+       }
+       freq_ref = (da7219->mclk_rate / indiv);
+       pll_ctrl = indiv_bits;
+
+       /* Configure PLL */
+       switch (source) {
+       case DA7219_SYSCLK_MCLK:
+               pll_ctrl |= DA7219_PLL_MODE_BYPASS;
+               snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+                                   DA7219_PLL_INDIV_MASK |
+                                   DA7219_PLL_MODE_MASK, pll_ctrl);
+               return 0;
+       case DA7219_SYSCLK_PLL:
+               pll_ctrl |= DA7219_PLL_MODE_NORMAL;
+               break;
+       case DA7219_SYSCLK_PLL_SRM:
+               pll_ctrl |= DA7219_PLL_MODE_SRM;
+               break;
+       case DA7219_SYSCLK_PLL_32KHZ:
+               pll_ctrl |= DA7219_PLL_MODE_32KHZ;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid PLL config\n");
+               return -EINVAL;
+       }
+
+       /* Calculate dividers for PLL */
+       pll_integer = fout / freq_ref;
+       frac_div = (u64)(fout % freq_ref) * 8192ULL;
+       do_div(frac_div, freq_ref);
+       pll_frac_top = (frac_div >> DA7219_BYTE_SHIFT) & DA7219_BYTE_MASK;
+       pll_frac_bot = (frac_div) & DA7219_BYTE_MASK;
+
+       /* Write PLL config & dividers */
+       snd_soc_write(codec, DA7219_PLL_FRAC_TOP, pll_frac_top);
+       snd_soc_write(codec, DA7219_PLL_FRAC_BOT, pll_frac_bot);
+       snd_soc_write(codec, DA7219_PLL_INTEGER, pll_integer);
+       snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+                           DA7219_PLL_INDIV_MASK | DA7219_PLL_MODE_MASK,
+                           pll_ctrl);
+
+       return 0;
+}
+
+static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               da7219->master = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               da7219->master = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+                               DA7219_DAI_CLK_POL_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               dai_ctrl |= DA7219_DAI_FORMAT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               dai_ctrl |= DA7219_DAI_FORMAT_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               dai_ctrl |= DA7219_DAI_FORMAT_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               dai_ctrl |= DA7219_DAI_FORMAT_DSP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* By default 64 BCLKs per WCLK is supported */
+       dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64;
+
+       snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+                           DA7219_DAI_BCLKS_PER_WCLK_MASK |
+                           DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK,
+                           dai_clk_mode);
+       snd_soc_update_bits(codec, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK,
+                           dai_ctrl);
+
+       return 0;
+}
+
+static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
+                                  unsigned int tx_mask, unsigned int rx_mask,
+                                  int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       u8 dai_bclks_per_wclk;
+       u16 offset;
+       u32 frame_size;
+
+       /* No channels enabled so disable TDM, revert to 64-bit frames */
+       if (!tx_mask) {
+               snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL,
+                                   DA7219_DAI_TDM_CH_EN_MASK |
+                                   DA7219_DAI_TDM_MODE_EN_MASK, 0);
+               snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+                                   DA7219_DAI_BCLKS_PER_WCLK_MASK,
+                                   DA7219_DAI_BCLKS_PER_WCLK_64);
+               return 0;
+       }
+
+       /* Check we have valid slots */
+       if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
+               dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+                       DA7219_DAI_TDM_MAX_SLOTS);
+               return -EINVAL;
+       }
+
+       /* Check we have a valid offset given */
+       if (rx_mask > DA7219_DAI_OFFSET_MAX) {
+               dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+                       DA7219_DAI_OFFSET_MAX);
+               return -EINVAL;
+       }
+
+       /* Calculate & validate frame size based on slot info provided. */
+       frame_size = slots * slot_width;
+       switch (frame_size) {
+       case 32:
+               dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
+               break;
+       case 64:
+               dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
+               break;
+       case 128:
+               dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
+               break;
+       case 256:
+               dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid frame size %d\n", frame_size);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+                           DA7219_DAI_BCLKS_PER_WCLK_MASK,
+                           dai_bclks_per_wclk);
+
+       offset = cpu_to_le16(rx_mask);
+       regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER,
+                         &offset, sizeof(offset));
+
+       snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL,
+                           DA7219_DAI_TDM_CH_EN_MASK |
+                           DA7219_DAI_TDM_MODE_EN_MASK,
+                           (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
+                           DA7219_DAI_TDM_MODE_EN_MASK);
+
+       return 0;
+}
+
+static int da7219_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 dai_ctrl = 0, fs;
+       unsigned int channels;
+
+       switch (params_width(params)) {
+       case 16:
+               dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
+               break;
+       case 20:
+               dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
+               break;
+       case 24:
+               dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
+               break;
+       case 32:
+               dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       channels = params_channels(params);
+       if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) {
+               dev_err(codec->dev,
+                       "Invalid number of channels, only 1 to %d supported\n",
+                       DA7219_DAI_CH_NUM_MAX);
+               return -EINVAL;
+       }
+       dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs = DA7219_SR_8000;
+               break;
+       case 11025:
+               fs = DA7219_SR_11025;
+               break;
+       case 12000:
+               fs = DA7219_SR_12000;
+               break;
+       case 16000:
+               fs = DA7219_SR_16000;
+               break;
+       case 22050:
+               fs = DA7219_SR_22050;
+               break;
+       case 24000:
+               fs = DA7219_SR_24000;
+               break;
+       case 32000:
+               fs = DA7219_SR_32000;
+               break;
+       case 44100:
+               fs = DA7219_SR_44100;
+               break;
+       case 48000:
+               fs = DA7219_SR_48000;
+               break;
+       case 88200:
+               fs = DA7219_SR_88200;
+               break;
+       case 96000:
+               fs = DA7219_SR_96000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, DA7219_DAI_CTRL,
+                           DA7219_DAI_WORD_LENGTH_MASK |
+                           DA7219_DAI_CH_NUM_MASK,
+                           dai_ctrl);
+       snd_soc_write(codec, DA7219_SR, fs);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops da7219_dai_ops = {
+       .hw_params      = da7219_hw_params,
+       .set_sysclk     = da7219_set_dai_sysclk,
+       .set_pll        = da7219_set_dai_pll,
+       .set_fmt        = da7219_set_dai_fmt,
+       .set_tdm_slot   = da7219_set_dai_tdm_slot,
+};
+
+#define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7219_dai = {
+       .name = "da7219-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = DA7219_DAI_CH_NUM_MAX,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7219_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = DA7219_DAI_CH_NUM_MAX,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA7219_FORMATS,
+       },
+       .ops = &da7219_dai_ops,
+       .symmetric_rates = 1,
+       .symmetric_channels = 1,
+       .symmetric_samplebits = 1,
+};
+
+
+/*
+ * DT
+ */
+
+static const struct of_device_id da7219_of_match[] = {
+       { .compatible = "dlg,da7219", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, da7219_of_match);
+
+static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec,
+                                                u32 val)
+{
+       switch (val) {
+       case 1050:
+               return DA7219_LDO_LVL_SEL_1_05V;
+       case 1100:
+               return DA7219_LDO_LVL_SEL_1_10V;
+       case 1200:
+               return DA7219_LDO_LVL_SEL_1_20V;
+       case 1400:
+               return DA7219_LDO_LVL_SEL_1_40V;
+       default:
+               dev_warn(codec->dev, "Invalid LDO level");
+               return DA7219_LDO_LVL_SEL_1_05V;
+       }
+}
+
+static enum da7219_micbias_voltage
+       da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+{
+       switch (val) {
+       case 1800:
+               return DA7219_MICBIAS_1_8V;
+       case 2000:
+               return DA7219_MICBIAS_2_0V;
+       case 2200:
+               return DA7219_MICBIAS_2_2V;
+       case 2400:
+               return DA7219_MICBIAS_2_4V;
+       case 2600:
+               return DA7219_MICBIAS_2_6V;
+       default:
+               dev_warn(codec->dev, "Invalid micbias level");
+               return DA7219_MICBIAS_2_2V;
+       }
+}
+
+static enum da7219_mic_amp_in_sel
+       da7219_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str)
+{
+       if (!strcmp(str, "diff")) {
+               return DA7219_MIC_AMP_IN_SEL_DIFF;
+       } else if (!strcmp(str, "se_p")) {
+               return DA7219_MIC_AMP_IN_SEL_SE_P;
+       } else if (!strcmp(str, "se_n")) {
+               return DA7219_MIC_AMP_IN_SEL_SE_N;
+       } else {
+               dev_warn(codec->dev, "Invalid mic input type selection");
+               return DA7219_MIC_AMP_IN_SEL_DIFF;
+       }
+}
+
+static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec)
+{
+       struct device_node *np = codec->dev->of_node;
+       struct da7219_pdata *pdata;
+       const char *of_str;
+       u32 of_val32;
+
+       pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0)
+               pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32);
+
+       if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0)
+               pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32);
+       else
+               pdata->micbias_lvl = DA7219_MICBIAS_2_2V;
+
+       if (!of_property_read_string(np, "dlg,mic-amp-in-sel", &of_str))
+               pdata->mic_amp_in_sel = da7219_of_mic_amp_in_sel(codec, of_str);
+       else
+               pdata->mic_amp_in_sel = DA7219_MIC_AMP_IN_SEL_DIFF;
+
+       return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7219_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       /* MCLK */
+                       if (da7219->mclk) {
+                               ret = clk_prepare_enable(da7219->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable mclk\n");
+                                       return ret;
+                               }
+                       }
+
+                       /* Master bias */
+                       snd_soc_update_bits(codec, DA7219_REFERENCES,
+                                           DA7219_BIAS_EN_MASK,
+                                           DA7219_BIAS_EN_MASK);
+
+                       /* Enable Internal Digital LDO */
+                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
+                                           DA7219_LDO_EN_MASK,
+                                           DA7219_LDO_EN_MASK);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* Only disable if jack detection not active */
+               if (!da7219->aad->jack) {
+                       /* Bypass Internal Digital LDO */
+                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
+                                           DA7219_LDO_EN_MASK, 0);
+
+                       /* Master bias */
+                       snd_soc_update_bits(codec, DA7219_REFERENCES,
+                                           DA7219_BIAS_EN_MASK, 0);
+               }
+
+               /* MCLK */
+               if (da7219->mclk)
+                       clk_disable_unprepare(da7219->mclk);
+               break;
+       }
+
+       return 0;
+}
+
+static const char *da7219_supply_names[DA7219_NUM_SUPPLIES] = {
+       [DA7219_SUPPLY_VDD] = "VDD",
+       [DA7219_SUPPLY_VDDMIC] = "VDDMIC",
+       [DA7219_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7219_handle_supplies(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct regulator *vddio;
+       u8 io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+       int i, ret;
+
+       /* Get required supplies */
+       for (i = 0; i < DA7219_NUM_SUPPLIES; ++i)
+               da7219->supplies[i].supply = da7219_supply_names[i];
+
+       ret = devm_regulator_bulk_get(codec->dev, DA7219_NUM_SUPPLIES,
+                                     da7219->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to get supplies");
+               return ret;
+       }
+
+       /* Determine VDDIO voltage provided */
+       vddio = da7219->supplies[DA7219_SUPPLY_VDDIO].consumer;
+       ret = regulator_get_voltage(vddio);
+       if (ret < 1200000)
+               dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+       else if (ret < 2800000)
+               io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V;
+
+       /* Enable main supplies */
+       ret = regulator_bulk_enable(DA7219_NUM_SUPPLIES, da7219->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies");
+               return ret;
+       }
+
+       /* Ensure device in active mode */
+       snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK);
+
+       /* Update IO voltage level range */
+       snd_soc_write(codec, DA7219_IO_CTRL, io_voltage_lvl);
+
+       return 0;
+}
+
+static void da7219_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       struct da7219_pdata *pdata = da7219->pdata;
+
+       if (pdata) {
+               u8 micbias_lvl = 0;
+
+               /* Internal LDO */
+               switch (pdata->ldo_lvl_sel) {
+               case DA7219_LDO_LVL_SEL_1_05V:
+               case DA7219_LDO_LVL_SEL_1_10V:
+               case DA7219_LDO_LVL_SEL_1_20V:
+               case DA7219_LDO_LVL_SEL_1_40V:
+                       snd_soc_update_bits(codec, DA7219_LDO_CTRL,
+                                           DA7219_LDO_LEVEL_SELECT_MASK,
+                                           (pdata->ldo_lvl_sel <<
+                                            DA7219_LDO_LEVEL_SELECT_SHIFT));
+                       break;
+               }
+
+               /* Mic Bias voltages */
+               switch (pdata->micbias_lvl) {
+               case DA7219_MICBIAS_1_8V:
+               case DA7219_MICBIAS_2_0V:
+               case DA7219_MICBIAS_2_2V:
+               case DA7219_MICBIAS_2_4V:
+               case DA7219_MICBIAS_2_6V:
+                       micbias_lvl |= (pdata->micbias_lvl <<
+                                       DA7219_MICBIAS1_LEVEL_SHIFT);
+                       break;
+               }
+
+               snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_lvl);
+
+               /* Mic */
+               switch (pdata->mic_amp_in_sel) {
+               case DA7219_MIC_AMP_IN_SEL_DIFF:
+               case DA7219_MIC_AMP_IN_SEL_SE_P:
+               case DA7219_MIC_AMP_IN_SEL_SE_N:
+                       snd_soc_write(codec, DA7219_MIC_1_SELECT,
+                                     pdata->mic_amp_in_sel);
+                       break;
+               }
+       }
+}
+
+static int da7219_probe(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mutex_init(&da7219->lock);
+
+       /* Regulator configuration */
+       ret = da7219_handle_supplies(codec);
+       if (ret)
+               return ret;
+
+       /* Handle DT/Platform data */
+       if (codec->dev->of_node)
+               da7219->pdata = da7219_of_to_pdata(codec);
+       else
+               da7219->pdata = dev_get_platdata(codec->dev);
+
+       da7219_handle_pdata(codec);
+
+       /* Check if MCLK provided */
+       da7219->mclk = devm_clk_get(codec->dev, "mclk");
+       if (IS_ERR(da7219->mclk)) {
+               if (PTR_ERR(da7219->mclk) != -ENOENT)
+                       return PTR_ERR(da7219->mclk);
+               else
+                       da7219->mclk = NULL;
+       }
+
+       /* Default PC counter to free-running */
+       snd_soc_update_bits(codec, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK,
+                           DA7219_PC_FREERUN_MASK);
+
+       /* Default gain ramping */
+       snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL,
+                           DA7219_MIXIN_L_AMP_RAMP_EN_MASK,
+                           DA7219_MIXIN_L_AMP_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_ADC_L_CTRL, DA7219_ADC_L_RAMP_EN_MASK,
+                           DA7219_ADC_L_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_DAC_L_CTRL, DA7219_DAC_L_RAMP_EN_MASK,
+                           DA7219_DAC_L_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_DAC_R_CTRL, DA7219_DAC_R_RAMP_EN_MASK,
+                           DA7219_DAC_R_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_RAMP_EN_MASK,
+                           DA7219_HP_L_AMP_RAMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_RAMP_EN_MASK,
+                           DA7219_HP_R_AMP_RAMP_EN_MASK);
+
+       /* Default infinite tone gen, start/stop by Kcontrol */
+       snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
+
+       /* Initialise AAD block */
+       return da7219_aad_init(codec);
+}
+
+static int da7219_remove(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       da7219_aad_exit(codec);
+
+       /* Supplies */
+       return regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+}
+
+#ifdef CONFIG_PM
+static int da7219_suspend(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       /* Put device into standby mode if jack detection disabled */
+       if (!da7219->aad->jack)
+               snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0);
+
+       return 0;
+}
+
+static int da7219_resume(struct snd_soc_codec *codec)
+{
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       /* Put device into active mode if previously pushed to standby */
+       if (!da7219->aad->jack)
+               snd_soc_write(codec, DA7219_SYSTEM_ACTIVE,
+                             DA7219_SYSTEM_ACTIVE_MASK);
+
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define da7219_suspend NULL
+#define da7219_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_da7219 = {
+       .probe                  = da7219_probe,
+       .remove                 = da7219_remove,
+       .suspend                = da7219_suspend,
+       .resume                 = da7219_resume,
+       .set_bias_level         = da7219_set_bias_level,
+
+       .controls               = da7219_snd_controls,
+       .num_controls           = ARRAY_SIZE(da7219_snd_controls),
+
+       .dapm_widgets           = da7219_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(da7219_dapm_widgets),
+       .dapm_routes            = da7219_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(da7219_audio_map),
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7219_reg_defaults[] = {
+       { DA7219_MIC_1_SELECT, 0x00 },
+       { DA7219_CIF_TIMEOUT_CTRL, 0x01 },
+       { DA7219_SR_24_48, 0x00 },
+       { DA7219_SR, 0x0A },
+       { DA7219_CIF_I2C_ADDR_CFG, 0x02 },
+       { DA7219_PLL_CTRL, 0x10 },
+       { DA7219_PLL_FRAC_TOP, 0x00 },
+       { DA7219_PLL_FRAC_BOT, 0x00 },
+       { DA7219_PLL_INTEGER, 0x20 },
+       { DA7219_DIG_ROUTING_DAI, 0x10 },
+       { DA7219_DAI_CLK_MODE, 0x01 },
+       { DA7219_DAI_CTRL, 0x28 },
+       { DA7219_DAI_TDM_CTRL, 0x40 },
+       { DA7219_DIG_ROUTING_DAC, 0x32 },
+       { DA7219_DAI_OFFSET_LOWER, 0x00 },
+       { DA7219_DAI_OFFSET_UPPER, 0x00 },
+       { DA7219_REFERENCES, 0x00 },
+       { DA7219_MIXIN_L_SELECT, 0x00 },
+       { DA7219_MIXIN_L_GAIN, 0x03 },
+       { DA7219_ADC_L_GAIN, 0x6F },
+       { DA7219_ADC_FILTERS1, 0x80 },
+       { DA7219_MIC_1_GAIN, 0x01 },
+       { DA7219_SIDETONE_CTRL, 0x40 },
+       { DA7219_SIDETONE_GAIN, 0x0E },
+       { DA7219_DROUTING_ST_OUTFILT_1L, 0x01 },
+       { DA7219_DROUTING_ST_OUTFILT_1R, 0x02 },
+       { DA7219_DAC_FILTERS5, 0x00 },
+       { DA7219_DAC_FILTERS2, 0x88 },
+       { DA7219_DAC_FILTERS3, 0x88 },
+       { DA7219_DAC_FILTERS4, 0x08 },
+       { DA7219_DAC_FILTERS1, 0x80 },
+       { DA7219_DAC_L_GAIN, 0x6F },
+       { DA7219_DAC_R_GAIN, 0x6F },
+       { DA7219_CP_CTRL, 0x20 },
+       { DA7219_HP_L_GAIN, 0x39 },
+       { DA7219_HP_R_GAIN, 0x39 },
+       { DA7219_MIXOUT_L_SELECT, 0x00 },
+       { DA7219_MIXOUT_R_SELECT, 0x00 },
+       { DA7219_MICBIAS_CTRL, 0x03 },
+       { DA7219_MIC_1_CTRL, 0x40 },
+       { DA7219_MIXIN_L_CTRL, 0x40 },
+       { DA7219_ADC_L_CTRL, 0x40 },
+       { DA7219_DAC_L_CTRL, 0x40 },
+       { DA7219_DAC_R_CTRL, 0x40 },
+       { DA7219_HP_L_CTRL, 0x40 },
+       { DA7219_HP_R_CTRL, 0x40 },
+       { DA7219_MIXOUT_L_CTRL, 0x10 },
+       { DA7219_MIXOUT_R_CTRL, 0x10 },
+       { DA7219_CHIP_ID1, 0x23 },
+       { DA7219_CHIP_ID2, 0x93 },
+       { DA7219_CHIP_REVISION, 0x00 },
+       { DA7219_LDO_CTRL, 0x00 },
+       { DA7219_IO_CTRL, 0x00 },
+       { DA7219_GAIN_RAMP_CTRL, 0x00 },
+       { DA7219_PC_COUNT, 0x02 },
+       { DA7219_CP_VOL_THRESHOLD1, 0x0E },
+       { DA7219_DIG_CTRL, 0x00 },
+       { DA7219_ALC_CTRL2, 0x00 },
+       { DA7219_ALC_CTRL3, 0x00 },
+       { DA7219_ALC_NOISE, 0x3F },
+       { DA7219_ALC_TARGET_MIN, 0x3F },
+       { DA7219_ALC_TARGET_MAX, 0x00 },
+       { DA7219_ALC_GAIN_LIMITS, 0xFF },
+       { DA7219_ALC_ANA_GAIN_LIMITS, 0x71 },
+       { DA7219_ALC_ANTICLIP_CTRL, 0x00 },
+       { DA7219_ALC_ANTICLIP_LEVEL, 0x00 },
+       { DA7219_DAC_NG_SETUP_TIME, 0x00 },
+       { DA7219_DAC_NG_OFF_THRESH, 0x00 },
+       { DA7219_DAC_NG_ON_THRESH, 0x00 },
+       { DA7219_DAC_NG_CTRL, 0x00 },
+       { DA7219_TONE_GEN_CFG1, 0x00 },
+       { DA7219_TONE_GEN_CFG2, 0x00 },
+       { DA7219_TONE_GEN_CYCLES, 0x00 },
+       { DA7219_TONE_GEN_FREQ1_L, 0x55 },
+       { DA7219_TONE_GEN_FREQ1_U, 0x15 },
+       { DA7219_TONE_GEN_FREQ2_L, 0x00 },
+       { DA7219_TONE_GEN_FREQ2_U, 0x40 },
+       { DA7219_TONE_GEN_ON_PER, 0x02 },
+       { DA7219_TONE_GEN_OFF_PER, 0x01 },
+       { DA7219_ACCDET_IRQ_MASK_A, 0x00 },
+       { DA7219_ACCDET_IRQ_MASK_B, 0x00 },
+       { DA7219_ACCDET_CONFIG_1, 0xD6 },
+       { DA7219_ACCDET_CONFIG_2, 0x34 },
+       { DA7219_ACCDET_CONFIG_3, 0x0A },
+       { DA7219_ACCDET_CONFIG_4, 0x16 },
+       { DA7219_ACCDET_CONFIG_5, 0x21 },
+       { DA7219_ACCDET_CONFIG_6, 0x3E },
+       { DA7219_ACCDET_CONFIG_7, 0x01 },
+       { DA7219_SYSTEM_ACTIVE, 0x00 },
+};
+
+static bool da7219_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DA7219_MIC_1_GAIN_STATUS:
+       case DA7219_MIXIN_L_GAIN_STATUS:
+       case DA7219_ADC_L_GAIN_STATUS:
+       case DA7219_DAC_L_GAIN_STATUS:
+       case DA7219_DAC_R_GAIN_STATUS:
+       case DA7219_HP_L_GAIN_STATUS:
+       case DA7219_HP_R_GAIN_STATUS:
+       case DA7219_CIF_CTRL:
+       case DA7219_PLL_SRM_STS:
+       case DA7219_ALC_CTRL1:
+       case DA7219_SYSTEM_MODES_INPUT:
+       case DA7219_SYSTEM_MODES_OUTPUT:
+       case DA7219_ALC_OFFSET_AUTO_M_L:
+       case DA7219_ALC_OFFSET_AUTO_U_L:
+       case DA7219_TONE_GEN_CFG1:
+       case DA7219_ACCDET_STATUS_A:
+       case DA7219_ACCDET_STATUS_B:
+       case DA7219_ACCDET_IRQ_EVENT_A:
+       case DA7219_ACCDET_IRQ_EVENT_B:
+       case DA7219_ACCDET_CONFIG_8:
+       case DA7219_SYSTEM_STATUS:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static const struct regmap_config da7219_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = DA7219_SYSTEM_ACTIVE,
+       .reg_defaults = da7219_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(da7219_reg_defaults),
+       .volatile_reg = da7219_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7219_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct da7219_priv *da7219;
+       int ret;
+
+       da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv),
+                             GFP_KERNEL);
+       if (!da7219)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, da7219);
+
+       da7219->regmap = devm_regmap_init_i2c(i2c, &da7219_regmap_config);
+       if (IS_ERR(da7219->regmap)) {
+               ret = PTR_ERR(da7219->regmap);
+               dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219,
+                                    &da7219_dai, 1);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register da7219 codec: %d\n",
+                       ret);
+       }
+       return ret;
+}
+
+static int da7219_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id da7219_i2c_id[] = {
+       { "da7219", },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, da7219_i2c_id);
+
+static struct i2c_driver da7219_i2c_driver = {
+       .driver = {
+               .name = "da7219",
+               .of_match_table = of_match_ptr(da7219_of_match),
+       },
+       .probe          = da7219_i2c_probe,
+       .remove         = da7219_i2c_remove,
+       .id_table       = da7219_i2c_id,
+};
+
+module_i2c_driver(da7219_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7219 Codec Driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
new file mode 100644 (file)
index 0000000..b514268
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * da7219.h - DA7219 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_H
+#define __DA7219_H
+
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7219.h>
+
+/*
+ * Registers
+ */
+
+#define DA7219_MIC_1_GAIN_STATUS       0x6
+#define DA7219_MIXIN_L_GAIN_STATUS     0x8
+#define DA7219_ADC_L_GAIN_STATUS       0xA
+#define DA7219_DAC_L_GAIN_STATUS       0xC
+#define DA7219_DAC_R_GAIN_STATUS       0xD
+#define DA7219_HP_L_GAIN_STATUS                0xE
+#define DA7219_HP_R_GAIN_STATUS                0xF
+#define DA7219_MIC_1_SELECT            0x10
+#define DA7219_CIF_TIMEOUT_CTRL                0x12
+#define DA7219_CIF_CTRL                        0x13
+#define DA7219_SR_24_48                        0x16
+#define DA7219_SR                      0x17
+#define DA7219_CIF_I2C_ADDR_CFG                0x1B
+#define DA7219_PLL_CTRL                        0x20
+#define DA7219_PLL_FRAC_TOP            0x22
+#define DA7219_PLL_FRAC_BOT            0x23
+#define DA7219_PLL_INTEGER             0x24
+#define DA7219_PLL_SRM_STS             0x25
+#define DA7219_DIG_ROUTING_DAI         0x2A
+#define DA7219_DAI_CLK_MODE            0x2B
+#define DA7219_DAI_CTRL                        0x2C
+#define DA7219_DAI_TDM_CTRL            0x2D
+#define DA7219_DIG_ROUTING_DAC         0x2E
+#define DA7219_ALC_CTRL1               0x2F
+#define DA7219_DAI_OFFSET_LOWER                0x30
+#define DA7219_DAI_OFFSET_UPPER                0x31
+#define DA7219_REFERENCES              0x32
+#define DA7219_MIXIN_L_SELECT          0x33
+#define DA7219_MIXIN_L_GAIN            0x34
+#define DA7219_ADC_L_GAIN              0x36
+#define DA7219_ADC_FILTERS1            0x38
+#define DA7219_MIC_1_GAIN              0x39
+#define DA7219_SIDETONE_CTRL           0x3A
+#define DA7219_SIDETONE_GAIN           0x3B
+#define DA7219_DROUTING_ST_OUTFILT_1L  0x3C
+#define DA7219_DROUTING_ST_OUTFILT_1R  0x3D
+#define DA7219_DAC_FILTERS5            0x40
+#define DA7219_DAC_FILTERS2            0x41
+#define DA7219_DAC_FILTERS3            0x42
+#define DA7219_DAC_FILTERS4            0x43
+#define DA7219_DAC_FILTERS1            0x44
+#define DA7219_DAC_L_GAIN              0x45
+#define DA7219_DAC_R_GAIN              0x46
+#define DA7219_CP_CTRL                 0x47
+#define DA7219_HP_L_GAIN               0x48
+#define DA7219_HP_R_GAIN               0x49
+#define DA7219_MIXOUT_L_SELECT         0x4B
+#define DA7219_MIXOUT_R_SELECT         0x4C
+#define DA7219_SYSTEM_MODES_INPUT      0x50
+#define DA7219_SYSTEM_MODES_OUTPUT     0x51
+#define DA7219_MICBIAS_CTRL            0x62
+#define DA7219_MIC_1_CTRL              0x63
+#define DA7219_MIXIN_L_CTRL            0x65
+#define DA7219_ADC_L_CTRL              0x67
+#define DA7219_DAC_L_CTRL              0x69
+#define DA7219_DAC_R_CTRL              0x6A
+#define DA7219_HP_L_CTRL               0x6B
+#define DA7219_HP_R_CTRL               0x6C
+#define DA7219_MIXOUT_L_CTRL           0x6E
+#define DA7219_MIXOUT_R_CTRL           0x6F
+#define DA7219_CHIP_ID1                        0x81
+#define DA7219_CHIP_ID2                        0x82
+#define DA7219_CHIP_REVISION           0x83
+#define DA7219_LDO_CTRL                        0x90
+#define DA7219_IO_CTRL                 0x91
+#define DA7219_GAIN_RAMP_CTRL          0x92
+#define DA7219_PC_COUNT                        0x94
+#define DA7219_CP_VOL_THRESHOLD1       0x95
+#define DA7219_CP_DELAY                        0x96
+#define DA7219_DIG_CTRL                        0x99
+#define DA7219_ALC_CTRL2               0x9A
+#define DA7219_ALC_CTRL3               0x9B
+#define DA7219_ALC_NOISE               0x9C
+#define DA7219_ALC_TARGET_MIN          0x9D
+#define DA7219_ALC_TARGET_MAX          0x9E
+#define DA7219_ALC_GAIN_LIMITS         0x9F
+#define DA7219_ALC_ANA_GAIN_LIMITS     0xA0
+#define DA7219_ALC_ANTICLIP_CTRL       0xA1
+#define DA7219_ALC_ANTICLIP_LEVEL      0xA2
+#define DA7219_ALC_OFFSET_AUTO_M_L     0xA3
+#define DA7219_ALC_OFFSET_AUTO_U_L     0xA4
+#define DA7219_DAC_NG_SETUP_TIME       0xAF
+#define DA7219_DAC_NG_OFF_THRESH       0xB0
+#define DA7219_DAC_NG_ON_THRESH                0xB1
+#define DA7219_DAC_NG_CTRL             0xB2
+#define DA7219_TONE_GEN_CFG1           0xB4
+#define DA7219_TONE_GEN_CFG2           0xB5
+#define DA7219_TONE_GEN_CYCLES         0xB6
+#define DA7219_TONE_GEN_FREQ1_L                0xB7
+#define DA7219_TONE_GEN_FREQ1_U                0xB8
+#define DA7219_TONE_GEN_FREQ2_L                0xB9
+#define DA7219_TONE_GEN_FREQ2_U                0xBA
+#define DA7219_TONE_GEN_ON_PER         0xBB
+#define DA7219_TONE_GEN_OFF_PER                0xBC
+#define DA7219_SYSTEM_STATUS           0xE0
+#define DA7219_SYSTEM_ACTIVE           0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7219_SWITCH_EN_MAX           0x1
+
+/* DA7219_MIC_1_GAIN_STATUS = 0x6 */
+#define DA7219_MIC_1_AMP_GAIN_STATUS_SHIFT     0
+#define DA7219_MIC_1_AMP_GAIN_STATUS_MASK      (0x7 << 0)
+#define DA7219_MIC_1_AMP_GAIN_MAX              0x7
+
+/* DA7219_MIXIN_L_GAIN_STATUS = 0x8 */
+#define DA7219_MIXIN_L_AMP_GAIN_STATUS_SHIFT   0
+#define DA7219_MIXIN_L_AMP_GAIN_STATUS_MASK    (0xF << 0)
+
+/* DA7219_ADC_L_GAIN_STATUS = 0xA */
+#define DA7219_ADC_L_DIGITAL_GAIN_STATUS_SHIFT 0
+#define DA7219_ADC_L_DIGITAL_GAIN_STATUS_MASK  (0x7F << 0)
+
+/* DA7219_DAC_L_GAIN_STATUS = 0xC */
+#define DA7219_DAC_L_DIGITAL_GAIN_STATUS_SHIFT 0
+#define DA7219_DAC_L_DIGITAL_GAIN_STATUS_MASK  (0x7F << 0)
+
+/* DA7219_DAC_R_GAIN_STATUS = 0xD */
+#define DA7219_DAC_R_DIGITAL_GAIN_STATUS_SHIFT 0
+#define DA7219_DAC_R_DIGITAL_GAIN_STATUS_MASK  (0x7F << 0)
+
+/* DA7219_HP_L_GAIN_STATUS = 0xE */
+#define DA7219_HP_L_AMP_GAIN_STATUS_SHIFT      0
+#define DA7219_HP_L_AMP_GAIN_STATUS_MASK       (0x3F << 0)
+
+/* DA7219_HP_R_GAIN_STATUS = 0xF */
+#define DA7219_HP_R_AMP_GAIN_STATUS_SHIFT      0
+#define DA7219_HP_R_AMP_GAIN_STATUS_MASK       (0x3F << 0)
+
+/* DA7219_MIC_1_SELECT = 0x10 */
+#define DA7219_MIC_1_AMP_IN_SEL_SHIFT  0
+#define DA7219_MIC_1_AMP_IN_SEL_MASK   (0x3 << 0)
+
+/* DA7219_CIF_TIMEOUT_CTRL = 0x12 */
+#define DA7219_I2C_TIMEOUT_EN_SHIFT    0
+#define DA7219_I2C_TIMEOUT_EN_MASK     (0x1 << 0)
+
+/* DA7219_CIF_CTRL = 0x13 */
+#define DA7219_CIF_I2C_WRITE_MODE_SHIFT                0
+#define DA7219_CIF_I2C_WRITE_MODE_MASK         (0x1 << 0)
+#define DA7219_CIF_REG_SOFT_RESET_SHIFT                7
+#define DA7219_CIF_REG_SOFT_RESET_MASK         (0x1 << 7)
+
+/* DA7219_SR_24_48 = 0x16 */
+#define DA7219_SR_24_48_SHIFT  0
+#define DA7219_SR_24_48_MASK   (0x1 << 0)
+
+/* DA7219_SR = 0x17 */
+#define DA7219_SR_SHIFT                0
+#define DA7219_SR_MASK         (0xF << 0)
+#define DA7219_SR_8000         (0x01 << 0)
+#define DA7219_SR_11025                (0x02 << 0)
+#define DA7219_SR_12000                (0x03 << 0)
+#define DA7219_SR_16000                (0x05 << 0)
+#define DA7219_SR_22050                (0x06 << 0)
+#define DA7219_SR_24000                (0x07 << 0)
+#define DA7219_SR_32000                (0x09 << 0)
+#define DA7219_SR_44100                (0x0A << 0)
+#define DA7219_SR_48000                (0x0B << 0)
+#define DA7219_SR_88200                (0x0E << 0)
+#define DA7219_SR_96000                (0x0F << 0)
+
+/* DA7219_CIF_I2C_ADDR_CFG = 0x1B */
+#define DA7219_CIF_I2C_ADDR_CFG_SHIFT  0
+#define DA7219_CIF_I2C_ADDR_CFG_MASK   (0x3 << 0)
+
+/* DA7219_PLL_CTRL = 0x20 */
+#define DA7219_PLL_INDIV_SHIFT         2
+#define DA7219_PLL_INDIV_MASK          (0x7 << 2)
+#define DA7219_PLL_INDIV_2_5_MHZ       (0x0 << 2)
+#define DA7219_PLL_INDIV_5_10_MHZ      (0x1 << 2)
+#define DA7219_PLL_INDIV_10_20_MHZ     (0x2 << 2)
+#define DA7219_PLL_INDIV_20_40_MHZ     (0x3 << 2)
+#define DA7219_PLL_INDIV_40_54_MHZ     (0x4 << 2)
+#define DA7219_PLL_MCLK_SQR_EN_SHIFT   5
+#define DA7219_PLL_MCLK_SQR_EN_MASK    (0x1 << 5)
+#define DA7219_PLL_MODE_SHIFT          6
+#define DA7219_PLL_MODE_MASK           (0x3 << 6)
+#define DA7219_PLL_MODE_BYPASS         (0x0 << 6)
+#define DA7219_PLL_MODE_NORMAL         (0x1 << 6)
+#define DA7219_PLL_MODE_SRM            (0x2 << 6)
+#define DA7219_PLL_MODE_32KHZ          (0x3 << 6)
+
+/* DA7219_PLL_FRAC_TOP = 0x22 */
+#define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT        0
+#define DA7219_PLL_FBDIV_FRAC_TOP_MASK (0x1F << 0)
+
+/* DA7219_PLL_FRAC_BOT = 0x23 */
+#define DA7219_PLL_FBDIV_FRAC_BOT_SHIFT        0
+#define DA7219_PLL_FBDIV_FRAC_BOT_MASK (0xFF << 0)
+
+/* DA7219_PLL_INTEGER = 0x24 */
+#define DA7219_PLL_FBDIV_INTEGER_SHIFT 0
+#define DA7219_PLL_FBDIV_INTEGER_MASK  (0x7F << 0)
+
+/* DA7219_PLL_SRM_STS = 0x25 */
+#define DA7219_PLL_SRM_STATE_SHIFT     0
+#define DA7219_PLL_SRM_STATE_MASK      (0xF << 0)
+#define DA7219_PLL_SRM_STATUS_SHIFT    4
+#define DA7219_PLL_SRM_STATUS_MASK     (0xF << 4)
+#define DA7219_PLL_SRM_STS_SRM_LOCK    (0x1 << 7)
+
+/* DA7219_DIG_ROUTING_DAI = 0x2A */
+#define DA7219_DAI_L_SRC_SHIFT 0
+#define DA7219_DAI_L_SRC_MASK  (0x3 << 0)
+#define DA7219_DAI_R_SRC_SHIFT 4
+#define DA7219_DAI_R_SRC_MASK  (0x3 << 4)
+#define DA7219_OUT_SRC_MAX     4
+
+/* DA7219_DAI_CLK_MODE = 0x2B */
+#define DA7219_DAI_BCLKS_PER_WCLK_SHIFT        0
+#define DA7219_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_32   (0x0 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_64   (0x1 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_128  (0x2 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_256  (0x3 << 0)
+#define DA7219_DAI_CLK_POL_SHIFT       2
+#define DA7219_DAI_CLK_POL_MASK                (0x1 << 2)
+#define DA7219_DAI_CLK_POL_INV         (0x1 << 2)
+#define DA7219_DAI_WCLK_POL_SHIFT      3
+#define DA7219_DAI_WCLK_POL_MASK       (0x1 << 3)
+#define DA7219_DAI_WCLK_POL_INV                (0x1 << 3)
+#define DA7219_DAI_WCLK_TRI_STATE_SHIFT        4
+#define DA7219_DAI_WCLK_TRI_STATE_MASK (0x1 << 4)
+#define DA7219_DAI_CLK_EN_SHIFT                7
+#define DA7219_DAI_CLK_EN_MASK         (0x1 << 7)
+
+/* DA7219_DAI_CTRL = 0x2C */
+#define DA7219_DAI_FORMAT_SHIFT                0
+#define DA7219_DAI_FORMAT_MASK         (0x3 << 0)
+#define DA7219_DAI_FORMAT_I2S          (0x0 << 0)
+#define DA7219_DAI_FORMAT_LEFT_J       (0x1 << 0)
+#define DA7219_DAI_FORMAT_RIGHT_J      (0x2 << 0)
+#define DA7219_DAI_FORMAT_DSP          (0x3 << 0)
+#define DA7219_DAI_WORD_LENGTH_SHIFT   2
+#define DA7219_DAI_WORD_LENGTH_MASK    (0x3 << 2)
+#define DA7219_DAI_WORD_LENGTH_S16_LE  (0x0 << 2)
+#define DA7219_DAI_WORD_LENGTH_S20_LE  (0x1 << 2)
+#define DA7219_DAI_WORD_LENGTH_S24_LE  (0x2 << 2)
+#define DA7219_DAI_WORD_LENGTH_S32_LE  (0x3 << 2)
+#define DA7219_DAI_CH_NUM_SHIFT                4
+#define DA7219_DAI_CH_NUM_MASK         (0x3 << 4)
+#define DA7219_DAI_CH_NUM_MAX          2
+#define DA7219_DAI_EN_SHIFT            7
+#define DA7219_DAI_EN_MASK             (0x1 << 7)
+
+/* DA7219_DAI_TDM_CTRL = 0x2D */
+#define DA7219_DAI_TDM_CH_EN_SHIFT     0
+#define DA7219_DAI_TDM_CH_EN_MASK      (0x3 << 0)
+#define DA7219_DAI_OE_SHIFT            6
+#define DA7219_DAI_OE_MASK             (0x1 << 6)
+#define DA7219_DAI_TDM_MODE_EN_SHIFT   7
+#define DA7219_DAI_TDM_MODE_EN_MASK    (0x1 << 7)
+#define DA7219_DAI_TDM_MAX_SLOTS       2
+
+/* DA7219_DIG_ROUTING_DAC = 0x2E */
+#define DA7219_DAC_L_SRC_SHIFT         0
+#define DA7219_DAC_L_SRC_MASK          (0x3 << 0)
+#define DA7219_DAC_L_SRC_TONEGEN       (0x1 << 0)
+#define DA7219_DAC_L_MONO_SHIFT                3
+#define DA7219_DAC_L_MONO_MASK         (0x1 << 3)
+#define DA7219_DAC_R_SRC_SHIFT         4
+#define DA7219_DAC_R_SRC_MASK          (0x3 << 4)
+#define DA7219_DAC_R_SRC_TONEGEN       (0x1 << 4)
+#define DA7219_DAC_R_MONO_SHIFT                7
+#define DA7219_DAC_R_MONO_MASK         (0x1 << 7)
+
+/* DA7219_ALC_CTRL1 = 0x2F */
+#define DA7219_ALC_OFFSET_EN_SHIFT     0
+#define DA7219_ALC_OFFSET_EN_MASK      (0x1 << 0)
+#define DA7219_ALC_SYNC_MODE_SHIFT     1
+#define DA7219_ALC_SYNC_MODE_MASK      (0x1 << 1)
+#define DA7219_ALC_EN_SHIFT            3
+#define DA7219_ALC_EN_MASK             (0x1 << 3)
+#define DA7219_ALC_AUTO_CALIB_EN_SHIFT 4
+#define DA7219_ALC_AUTO_CALIB_EN_MASK  (0x1 << 4)
+#define DA7219_ALC_CALIB_OVERFLOW_SHIFT        5
+#define DA7219_ALC_CALIB_OVERFLOW_MASK (0x1 << 5)
+
+/* DA7219_DAI_OFFSET_LOWER = 0x30 */
+#define DA7219_DAI_OFFSET_LOWER_SHIFT  0
+#define DA7219_DAI_OFFSET_LOWER_MASK   (0xFF << 0)
+
+/* DA7219_DAI_OFFSET_UPPER = 0x31 */
+#define DA7219_DAI_OFFSET_UPPER_SHIFT  0
+#define DA7219_DAI_OFFSET_UPPER_MASK   (0x7 << 0)
+#define DA7219_DAI_OFFSET_MAX          0x2FF
+
+/* DA7219_REFERENCES = 0x32 */
+#define DA7219_BIAS_EN_SHIFT           3
+#define DA7219_BIAS_EN_MASK            (0x1 << 3)
+#define DA7219_VMID_FAST_CHARGE_SHIFT  4
+#define DA7219_VMID_FAST_CHARGE_MASK   (0x1 << 4)
+
+/* DA7219_MIXIN_L_SELECT = 0x33 */
+#define DA7219_MIXIN_L_MIX_SELECT_SHIFT        0
+#define DA7219_MIXIN_L_MIX_SELECT_MASK (0x1 << 0)
+
+/* DA7219_MIXIN_L_GAIN = 0x34 */
+#define DA7219_MIXIN_L_AMP_GAIN_SHIFT  0
+#define DA7219_MIXIN_L_AMP_GAIN_MASK   (0xF << 0)
+#define DA7219_MIXIN_L_AMP_GAIN_MAX    0xF
+
+/* DA7219_ADC_L_GAIN = 0x36 */
+#define DA7219_ADC_L_DIGITAL_GAIN_SHIFT        0
+#define DA7219_ADC_L_DIGITAL_GAIN_MASK (0x7F << 0)
+#define DA7219_ADC_L_DIGITAL_GAIN_MAX  0x7F
+
+/* DA7219_ADC_FILTERS1 = 0x38 */
+#define DA7219_ADC_VOICE_HPF_CORNER_SHIFT      0
+#define DA7219_ADC_VOICE_HPF_CORNER_MASK       (0x7 << 0)
+#define DA7219_VOICE_HPF_CORNER_MAX            8
+#define DA7219_ADC_VOICE_EN_SHIFT              3
+#define DA7219_ADC_VOICE_EN_MASK               (0x1 << 3)
+#define DA7219_ADC_AUDIO_HPF_CORNER_SHIFT      4
+#define DA7219_ADC_AUDIO_HPF_CORNER_MASK       (0x3 << 4)
+#define DA7219_AUDIO_HPF_CORNER_MAX            4
+#define DA7219_ADC_HPF_EN_SHIFT                        7
+#define DA7219_ADC_HPF_EN_MASK                 (0x1 << 7)
+#define DA7219_HPF_MODE_SHIFT                  0
+#define DA7219_HPF_DISABLED                    ((0x0 << 3) | (0x0 << 7))
+#define DA7219_HPF_AUDIO_EN                    ((0x0 << 3) | (0x1 << 7))
+#define DA7219_HPF_VOICE_EN                    ((0x1 << 3) | (0x1 << 7))
+#define DA7219_HPF_MODE_MASK                   ((0x1 << 3) | (0x1 << 7))
+#define DA7219_HPF_MODE_MAX                    3
+
+/* DA7219_MIC_1_GAIN = 0x39 */
+#define DA7219_MIC_1_AMP_GAIN_SHIFT    0
+#define DA7219_MIC_1_AMP_GAIN_MASK     (0x7 << 0)
+
+/* DA7219_SIDETONE_CTRL = 0x3A */
+#define DA7219_SIDETONE_MUTE_EN_SHIFT  6
+#define DA7219_SIDETONE_MUTE_EN_MASK   (0x1 << 6)
+#define DA7219_SIDETONE_EN_SHIFT       7
+#define DA7219_SIDETONE_EN_MASK                (0x1 << 7)
+
+/* DA7219_SIDETONE_GAIN = 0x3B */
+#define DA7219_SIDETONE_GAIN_SHIFT     0
+#define DA7219_SIDETONE_GAIN_MASK      (0xF << 0)
+#define DA7219_SIDETONE_GAIN_MAX       0xE
+
+/* DA7219_DROUTING_ST_OUTFILT_1L = 0x3C */
+#define DA7219_OUTFILT_ST_1L_SRC_SHIFT         0
+#define DA7219_OUTFILT_ST_1L_SRC_MASK          (0x7 << 0)
+#define DA7219_DMIX_ST_SRC_OUTFILT1L_SHIFT     0
+#define DA7219_DMIX_ST_SRC_OUTFILT1R_SHIFT     1
+#define DA7219_DMIX_ST_SRC_SIDETONE_SHIFT      2
+#define DA7219_DMIX_ST_SRC_OUTFILT1L           (0x1 << 0)
+#define DA7219_DMIX_ST_SRC_OUTFILT1R           (0x1 << 1)
+
+/* DA7219_DROUTING_ST_OUTFILT_1R = 0x3D */
+#define DA7219_OUTFILT_ST_1R_SRC_SHIFT 0
+#define DA7219_OUTFILT_ST_1R_SRC_MASK  (0x7 << 0)
+
+/* DA7219_DAC_FILTERS5 = 0x40 */
+#define DA7219_DAC_SOFTMUTE_RATE_SHIFT 4
+#define DA7219_DAC_SOFTMUTE_RATE_MASK  (0x7 << 4)
+#define DA7219_DAC_SOFTMUTE_RATE_MAX   7
+#define DA7219_DAC_SOFTMUTE_EN_SHIFT   7
+#define DA7219_DAC_SOFTMUTE_EN_MASK    (0x1 << 7)
+
+/* DA7219_DAC_FILTERS2 = 0x41 */
+#define DA7219_DAC_EQ_BAND1_SHIFT      0
+#define DA7219_DAC_EQ_BAND1_MASK       (0xF << 0)
+#define DA7219_DAC_EQ_BAND2_SHIFT      4
+#define DA7219_DAC_EQ_BAND2_MASK       (0xF << 4)
+#define DA7219_DAC_EQ_BAND_MAX         0xF
+
+/* DA7219_DAC_FILTERS3 = 0x42 */
+#define DA7219_DAC_EQ_BAND3_SHIFT      0
+#define DA7219_DAC_EQ_BAND3_MASK       (0xF << 0)
+#define DA7219_DAC_EQ_BAND4_SHIFT      4
+#define DA7219_DAC_EQ_BAND4_MASK       (0xF << 4)
+
+/* DA7219_DAC_FILTERS4 = 0x43 */
+#define DA7219_DAC_EQ_BAND5_SHIFT      0
+#define DA7219_DAC_EQ_BAND5_MASK       (0xF << 0)
+#define DA7219_DAC_EQ_EN_SHIFT         7
+#define DA7219_DAC_EQ_EN_MASK          (0x1 << 7)
+
+/* DA7219_DAC_FILTERS1 = 0x44 */
+#define DA7219_DAC_VOICE_HPF_CORNER_SHIFT      0
+#define DA7219_DAC_VOICE_HPF_CORNER_MASK       (0x7 << 0)
+#define DA7219_DAC_VOICE_EN_SHIFT              3
+#define DA7219_DAC_VOICE_EN_MASK               (0x1 << 3)
+#define DA7219_DAC_AUDIO_HPF_CORNER_SHIFT      4
+#define DA7219_DAC_AUDIO_HPF_CORNER_MASK       (0x3 << 4)
+#define DA7219_DAC_HPF_EN_SHIFT                        7
+#define DA7219_DAC_HPF_EN_MASK                 (0x1 << 7)
+
+/* DA7219_DAC_L_GAIN = 0x45 */
+#define DA7219_DAC_L_DIGITAL_GAIN_SHIFT        0
+#define DA7219_DAC_L_DIGITAL_GAIN_MASK (0x7F << 0)
+#define DA7219_DAC_DIGITAL_GAIN_MAX    0x7F
+#define DA7219_DAC_DIGITAL_GAIN_0DB    (0x6F << 0)
+
+/* DA7219_DAC_R_GAIN = 0x46 */
+#define DA7219_DAC_R_DIGITAL_GAIN_SHIFT        0
+#define DA7219_DAC_R_DIGITAL_GAIN_MASK (0x7F << 0)
+
+/* DA7219_CP_CTRL = 0x47 */
+#define DA7219_CP_MCHANGE_SHIFT                4
+#define DA7219_CP_MCHANGE_MASK         (0x3 << 4)
+#define DA7219_CP_MCHANGE_REL_MASK     0x3
+#define DA7219_CP_MCHANGE_MAX          3
+#define DA7219_CP_MCHANGE_LARGEST_VOL  0x1
+#define DA7219_CP_MCHANGE_DAC_VOL      0x2
+#define DA7219_CP_MCHANGE_SIG_MAG      0x3
+#define DA7219_CP_EN_SHIFT             7
+#define DA7219_CP_EN_MASK              (0x1 << 7)
+
+/* DA7219_HP_L_GAIN = 0x48 */
+#define DA7219_HP_L_AMP_GAIN_SHIFT     0
+#define DA7219_HP_L_AMP_GAIN_MASK      (0x3F << 0)
+#define DA7219_HP_AMP_GAIN_MAX         0x3F
+#define DA7219_HP_AMP_GAIN_0DB         (0x39 << 0)
+
+/* DA7219_HP_R_GAIN = 0x49 */
+#define DA7219_HP_R_AMP_GAIN_SHIFT     0
+#define DA7219_HP_R_AMP_GAIN_MASK      (0x3F << 0)
+
+/* DA7219_MIXOUT_L_SELECT = 0x4B */
+#define DA7219_MIXOUT_L_MIX_SELECT_SHIFT       0
+#define DA7219_MIXOUT_L_MIX_SELECT_MASK                (0x1 << 0)
+
+/* DA7219_MIXOUT_R_SELECT = 0x4C */
+#define DA7219_MIXOUT_R_MIX_SELECT_SHIFT       0
+#define DA7219_MIXOUT_R_MIX_SELECT_MASK                (0x1 << 0)
+
+/* DA7219_SYSTEM_MODES_INPUT = 0x50 */
+#define DA7219_MODE_SUBMIT_SHIFT       0
+#define DA7219_MODE_SUBMIT_MASK                (0x1 << 0)
+#define DA7219_ADC_MODE_SHIFT          1
+#define DA7219_ADC_MODE_MASK           (0x7F << 1)
+
+/* DA7219_SYSTEM_MODES_OUTPUT = 0x51 */
+#define DA7219_MODE_SUBMIT_SHIFT       0
+#define DA7219_MODE_SUBMIT_MASK                (0x1 << 0)
+#define DA7219_DAC_MODE_SHIFT          1
+#define DA7219_DAC_MODE_MASK           (0x7F << 1)
+
+/* DA7219_MICBIAS_CTRL = 0x62 */
+#define DA7219_MICBIAS1_LEVEL_SHIFT    0
+#define DA7219_MICBIAS1_LEVEL_MASK     (0x7 << 0)
+#define DA7219_MICBIAS1_EN_SHIFT       3
+#define DA7219_MICBIAS1_EN_MASK                (0x1 << 3)
+
+/* DA7219_MIC_1_CTRL = 0x63 */
+#define DA7219_MIC_1_AMP_RAMP_EN_SHIFT 5
+#define DA7219_MIC_1_AMP_RAMP_EN_MASK  (0x1 << 5)
+#define DA7219_MIC_1_AMP_MUTE_EN_SHIFT 6
+#define DA7219_MIC_1_AMP_MUTE_EN_MASK  (0x1 << 6)
+#define DA7219_MIC_1_AMP_EN_SHIFT      7
+#define DA7219_MIC_1_AMP_EN_MASK       (0x1 << 7)
+
+/* DA7219_MIXIN_L_CTRL = 0x65 */
+#define DA7219_MIXIN_L_MIX_EN_SHIFT            3
+#define DA7219_MIXIN_L_MIX_EN_MASK             (0x1 << 3)
+#define DA7219_MIXIN_L_AMP_ZC_EN_SHIFT         4
+#define DA7219_MIXIN_L_AMP_ZC_EN_MASK          (0x1 << 4)
+#define DA7219_MIXIN_L_AMP_RAMP_EN_SHIFT       5
+#define DA7219_MIXIN_L_AMP_RAMP_EN_MASK                (0x1 << 5)
+#define DA7219_MIXIN_L_AMP_MUTE_EN_SHIFT       6
+#define DA7219_MIXIN_L_AMP_MUTE_EN_MASK                (0x1 << 6)
+#define DA7219_MIXIN_L_AMP_EN_SHIFT            7
+#define DA7219_MIXIN_L_AMP_EN_MASK             (0x1 << 7)
+
+/* DA7219_ADC_L_CTRL = 0x67 */
+#define DA7219_ADC_L_BIAS_SHIFT                0
+#define DA7219_ADC_L_BIAS_MASK         (0x3 << 0)
+#define DA7219_ADC_L_RAMP_EN_SHIFT     5
+#define DA7219_ADC_L_RAMP_EN_MASK      (0x1 << 5)
+#define DA7219_ADC_L_MUTE_EN_SHIFT     6
+#define DA7219_ADC_L_MUTE_EN_MASK      (0x1 << 6)
+#define DA7219_ADC_L_EN_SHIFT          7
+#define DA7219_ADC_L_EN_MASK           (0x1 << 7)
+
+/* DA7219_DAC_L_CTRL = 0x69 */
+#define DA7219_DAC_L_RAMP_EN_SHIFT     5
+#define DA7219_DAC_L_RAMP_EN_MASK      (0x1 << 5)
+#define DA7219_DAC_L_MUTE_EN_SHIFT     6
+#define DA7219_DAC_L_MUTE_EN_MASK      (0x1 << 6)
+#define DA7219_DAC_L_EN_SHIFT          7
+#define DA7219_DAC_L_EN_MASK           (0x1 << 7)
+
+/* DA7219_DAC_R_CTRL = 0x6A */
+#define DA7219_DAC_R_RAMP_EN_SHIFT     5
+#define DA7219_DAC_R_RAMP_EN_MASK      (0x1 << 5)
+#define DA7219_DAC_R_MUTE_EN_SHIFT     6
+#define DA7219_DAC_R_MUTE_EN_MASK      (0x1 << 6)
+#define DA7219_DAC_R_EN_SHIFT          7
+#define DA7219_DAC_R_EN_MASK           (0x1 << 7)
+
+/* DA7219_HP_L_CTRL = 0x6B */
+#define DA7219_HP_L_AMP_MIN_GAIN_EN_SHIFT      2
+#define DA7219_HP_L_AMP_MIN_GAIN_EN_MASK       (0x1 << 2)
+#define DA7219_HP_L_AMP_OE_SHIFT               3
+#define DA7219_HP_L_AMP_OE_MASK                        (0x1 << 3)
+#define DA7219_HP_L_AMP_ZC_EN_SHIFT            4
+#define DA7219_HP_L_AMP_ZC_EN_MASK             (0x1 << 4)
+#define DA7219_HP_L_AMP_RAMP_EN_SHIFT          5
+#define DA7219_HP_L_AMP_RAMP_EN_MASK           (0x1 << 5)
+#define DA7219_HP_L_AMP_MUTE_EN_SHIFT          6
+#define DA7219_HP_L_AMP_MUTE_EN_MASK           (0x1 << 6)
+#define DA7219_HP_L_AMP_EN_SHIFT               7
+#define DA7219_HP_L_AMP_EN_MASK                        (0x1 << 7)
+
+/* DA7219_HP_R_CTRL = 0x6C */
+#define DA7219_HP_R_AMP_MIN_GAIN_EN_SHIFT      2
+#define DA7219_HP_R_AMP_MIN_GAIN_EN_MASK       (0x1 << 2)
+#define DA7219_HP_R_AMP_OE_SHIFT               3
+#define DA7219_HP_R_AMP_OE_MASK                        (0x1 << 3)
+#define DA7219_HP_R_AMP_ZC_EN_SHIFT            4
+#define DA7219_HP_R_AMP_ZC_EN_MASK             (0x1 << 4)
+#define DA7219_HP_R_AMP_RAMP_EN_SHIFT          5
+#define DA7219_HP_R_AMP_RAMP_EN_MASK           (0x1 << 5)
+#define DA7219_HP_R_AMP_MUTE_EN_SHIFT          6
+#define DA7219_HP_R_AMP_MUTE_EN_MASK           (0x1 << 6)
+#define DA7219_HP_R_AMP_EN_SHIFT               7
+#define DA7219_HP_R_AMP_EN_MASK                        (0x1 << 7)
+
+/* DA7219_MIXOUT_L_CTRL = 0x6E */
+#define DA7219_MIXOUT_L_AMP_EN_SHIFT   7
+#define DA7219_MIXOUT_L_AMP_EN_MASK    (0x1 << 7)
+
+/* DA7219_MIXOUT_R_CTRL = 0x6F */
+#define DA7219_MIXOUT_R_AMP_EN_SHIFT   7
+#define DA7219_MIXOUT_R_AMP_EN_MASK    (0x1 << 7)
+
+/* DA7219_CHIP_ID1 = 0x81 */
+#define DA7219_CHIP_ID1_SHIFT  0
+#define DA7219_CHIP_ID1_MASK   (0xFF << 0)
+
+/* DA7219_CHIP_ID2 = 0x82 */
+#define DA7219_CHIP_ID2_SHIFT  0
+#define DA7219_CHIP_ID2_MASK   (0xFF << 0)
+
+/* DA7219_CHIP_REVISION = 0x83 */
+#define DA7219_CHIP_MINOR_SHIFT        0
+#define DA7219_CHIP_MINOR_MASK (0xF << 0)
+#define DA7219_CHIP_MAJOR_SHIFT        4
+#define DA7219_CHIP_MAJOR_MASK (0xF << 4)
+
+/* DA7219_LDO_CTRL = 0x90 */
+#define DA7219_LDO_LEVEL_SELECT_SHIFT  4
+#define DA7219_LDO_LEVEL_SELECT_MASK   (0x3 << 4)
+#define DA7219_LDO_EN_SHIFT            7
+#define DA7219_LDO_EN_MASK             (0x1 << 7)
+
+/* DA7219_IO_CTRL = 0x91 */
+#define DA7219_IO_VOLTAGE_LEVEL_SHIFT          0
+#define DA7219_IO_VOLTAGE_LEVEL_MASK           (0x1 << 0)
+#define DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V      0
+#define DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V      1
+
+/* DA7219_GAIN_RAMP_CTRL = 0x92 */
+#define DA7219_GAIN_RAMP_RATE_SHIFT    0
+#define DA7219_GAIN_RAMP_RATE_MASK     (0x3 << 0)
+#define DA7219_GAIN_RAMP_RATE_MAX      4
+
+/* DA7219_PC_COUNT = 0x94 */
+#define DA7219_PC_FREERUN_SHIFT                0
+#define DA7219_PC_FREERUN_MASK         (0x1 << 0)
+#define DA7219_PC_RESYNC_AUTO_SHIFT    1
+#define DA7219_PC_RESYNC_AUTO_MASK     (0x1 << 1)
+
+/* DA7219_CP_VOL_THRESHOLD1 = 0x95 */
+#define DA7219_CP_THRESH_VDD2_SHIFT    0
+#define DA7219_CP_THRESH_VDD2_MASK     (0x3F << 0)
+#define DA7219_CP_THRESH_VDD2_MAX      0x3F
+
+/* DA7219_DIG_CTRL = 0x99 */
+#define DA7219_DAC_L_INV_SHIFT 3
+#define DA7219_DAC_L_INV_MASK  (0x1 << 3)
+#define DA7219_DAC_R_INV_SHIFT 7
+#define DA7219_DAC_R_INV_MASK  (0x1 << 7)
+
+/* DA7219_ALC_CTRL2 = 0x9A */
+#define DA7219_ALC_ATTACK_SHIFT                0
+#define DA7219_ALC_ATTACK_MASK         (0xF << 0)
+#define DA7219_ALC_ATTACK_MAX          13
+#define DA7219_ALC_RELEASE_SHIFT       4
+#define DA7219_ALC_RELEASE_MASK                (0xF << 4)
+#define DA7219_ALC_RELEASE_MAX         11
+
+/* DA7219_ALC_CTRL3 = 0x9B */
+#define DA7219_ALC_HOLD_SHIFT          0
+#define DA7219_ALC_HOLD_MASK           (0xF << 0)
+#define DA7219_ALC_HOLD_MAX            16
+#define DA7219_ALC_INTEG_ATTACK_SHIFT  4
+#define DA7219_ALC_INTEG_ATTACK_MASK   (0x3 << 4)
+#define DA7219_ALC_INTEG_RELEASE_SHIFT 6
+#define DA7219_ALC_INTEG_RELEASE_MASK  (0x3 << 6)
+#define DA7219_ALC_INTEG_MAX           4
+
+/* DA7219_ALC_NOISE = 0x9C */
+#define DA7219_ALC_NOISE_SHIFT         0
+#define DA7219_ALC_NOISE_MASK          (0x3F << 0)
+#define DA7219_ALC_THRESHOLD_MAX       0x3F
+
+/* DA7219_ALC_TARGET_MIN = 0x9D */
+#define DA7219_ALC_THRESHOLD_MIN_SHIFT 0
+#define DA7219_ALC_THRESHOLD_MIN_MASK  (0x3F << 0)
+
+/* DA7219_ALC_TARGET_MAX = 0x9E */
+#define DA7219_ALC_THRESHOLD_MAX_SHIFT 0
+#define DA7219_ALC_THRESHOLD_MAX_MASK  (0x3F << 0)
+
+/* DA7219_ALC_GAIN_LIMITS = 0x9F */
+#define DA7219_ALC_ATTEN_MAX_SHIFT     0
+#define DA7219_ALC_ATTEN_MAX_MASK      (0xF << 0)
+#define DA7219_ALC_GAIN_MAX_SHIFT      4
+#define DA7219_ALC_GAIN_MAX_MASK       (0xF << 4)
+#define DA7219_ALC_ATTEN_GAIN_MAX      0xF
+
+/* DA7219_ALC_ANA_GAIN_LIMITS = 0xA0 */
+#define DA7219_ALC_ANA_GAIN_MIN_SHIFT  0
+#define DA7219_ALC_ANA_GAIN_MIN_MASK   (0x7 << 0)
+#define DA7219_ALC_ANA_GAIN_MIN                0x1
+#define DA7219_ALC_ANA_GAIN_MAX_SHIFT  4
+#define DA7219_ALC_ANA_GAIN_MAX_MASK   (0x7 << 4)
+#define DA7219_ALC_ANA_GAIN_MAX                0x7
+
+/* DA7219_ALC_ANTICLIP_CTRL = 0xA1 */
+#define DA7219_ALC_ANTICLIP_STEP_SHIFT 0
+#define DA7219_ALC_ANTICLIP_STEP_MASK  (0x3 << 0)
+#define DA7219_ALC_ANTICLIP_STEP_MAX   4
+#define DA7219_ALC_ANTIPCLIP_EN_SHIFT  7
+#define DA7219_ALC_ANTIPCLIP_EN_MASK   (0x1 << 7)
+
+/* DA7219_ALC_ANTICLIP_LEVEL = 0xA2 */
+#define DA7219_ALC_ANTICLIP_LEVEL_SHIFT        0
+#define DA7219_ALC_ANTICLIP_LEVEL_MASK (0x7F << 0)
+
+/* DA7219_ALC_OFFSET_AUTO_M_L = 0xA3 */
+#define DA7219_ALC_OFFSET_AUTO_M_L_SHIFT       0
+#define DA7219_ALC_OFFSET_AUTO_M_L_MASK                (0xFF << 0)
+
+/* DA7219_ALC_OFFSET_AUTO_U_L = 0xA4 */
+#define DA7219_ALC_OFFSET_AUTO_U_L_SHIFT       0
+#define DA7219_ALC_OFFSET_AUTO_U_L_MASK                (0xF << 0)
+
+/* DA7219_DAC_NG_SETUP_TIME = 0xAF */
+#define DA7219_DAC_NG_SETUP_TIME_SHIFT 0
+#define DA7219_DAC_NG_SETUP_TIME_MASK  (0x3 << 0)
+#define DA7219_DAC_NG_SETUP_TIME_MAX   4
+#define DA7219_DAC_NG_RAMPUP_RATE_SHIFT        2
+#define DA7219_DAC_NG_RAMPUP_RATE_MASK (0x1 << 2)
+#define DA7219_DAC_NG_RAMPDN_RATE_SHIFT        3
+#define DA7219_DAC_NG_RAMPDN_RATE_MASK (0x1 << 3)
+#define DA7219_DAC_NG_RAMP_RATE_MAX    2
+
+/* DA7219_DAC_NG_OFF_THRESH = 0xB0 */
+#define DA7219_DAC_NG_OFF_THRESHOLD_SHIFT      0
+#define DA7219_DAC_NG_OFF_THRESHOLD_MASK       (0x7 << 0)
+#define DA7219_DAC_NG_THRESHOLD_MAX            0x7
+
+/* DA7219_DAC_NG_ON_THRESH = 0xB1 */
+#define DA7219_DAC_NG_ON_THRESHOLD_SHIFT       0
+#define DA7219_DAC_NG_ON_THRESHOLD_MASK                (0x7 << 0)
+
+/* DA7219_DAC_NG_CTRL = 0xB2 */
+#define DA7219_DAC_NG_EN_SHIFT 7
+#define DA7219_DAC_NG_EN_MASK  (0x1 << 7)
+
+/* DA7219_TONE_GEN_CFG1 = 0xB4 */
+#define DA7219_DTMF_REG_SHIFT          0
+#define DA7219_DTMF_REG_MASK           (0xF << 0)
+#define DA7219_DTMF_REG_MAX            16
+#define DA7219_DTMF_EN_SHIFT           4
+#define DA7219_DTMF_EN_MASK            (0x1 << 4)
+#define DA7219_START_STOPN_SHIFT       7
+#define DA7219_START_STOPN_MASK                (0x1 << 7)
+
+/* DA7219_TONE_GEN_CFG2 = 0xB5 */
+#define DA7219_SWG_SEL_SHIFT           0
+#define DA7219_SWG_SEL_MASK            (0x3 << 0)
+#define DA7219_SWG_SEL_MAX             4
+#define DA7219_SWG_SEL_SRAMP           (0x3 << 0)
+#define DA7219_TONE_GEN_GAIN_SHIFT     4
+#define DA7219_TONE_GEN_GAIN_MASK      (0xF << 4)
+#define DA7219_TONE_GEN_GAIN_MAX       0xF
+#define DA7219_TONE_GEN_GAIN_MINUS_9DB (0x3 << 4)
+#define DA7219_TONE_GEN_GAIN_MINUS_15DB        (0x5 << 4)
+
+/* DA7219_TONE_GEN_CYCLES = 0xB6 */
+#define DA7219_BEEP_CYCLES_SHIFT       0
+#define DA7219_BEEP_CYCLES_MASK                (0x7 << 0)
+
+/* DA7219_TONE_GEN_FREQ1_L = 0xB7 */
+#define DA7219_FREQ1_L_SHIFT   0
+#define DA7219_FREQ1_L_MASK    (0xFF << 0)
+#define DA7219_FREQ_MAX                0xFFFF
+
+/* DA7219_TONE_GEN_FREQ1_U = 0xB8 */
+#define DA7219_FREQ1_U_SHIFT   0
+#define DA7219_FREQ1_U_MASK    (0xFF << 0)
+
+/* DA7219_TONE_GEN_FREQ2_L = 0xB9 */
+#define DA7219_FREQ2_L_SHIFT   0
+#define DA7219_FREQ2_L_MASK    (0xFF << 0)
+
+/* DA7219_TONE_GEN_FREQ2_U = 0xBA */
+#define DA7219_FREQ2_U_SHIFT   0
+#define DA7219_FREQ2_U_MASK    (0xFF << 0)
+
+/* DA7219_TONE_GEN_ON_PER = 0xBB */
+#define DA7219_BEEP_ON_PER_SHIFT       0
+#define DA7219_BEEP_ON_PER_MASK                (0x3F << 0)
+#define DA7219_BEEP_ON_OFF_MAX         0x3F
+
+/* DA7219_TONE_GEN_OFF_PER = 0xBC */
+#define DA7219_BEEP_OFF_PER_SHIFT      0
+#define DA7219_BEEP_OFF_PER_MASK       (0x3F << 0)
+
+/* DA7219_SYSTEM_STATUS = 0xE0 */
+#define DA7219_SC1_BUSY_SHIFT  0
+#define DA7219_SC1_BUSY_MASK   (0x1 << 0)
+#define DA7219_SC2_BUSY_SHIFT  1
+#define DA7219_SC2_BUSY_MASK   (0x1 << 1)
+
+/* DA7219_SYSTEM_ACTIVE = 0xFD */
+#define DA7219_SYSTEM_ACTIVE_SHIFT     0
+#define DA7219_SYSTEM_ACTIVE_MASK      (0x1 << 0)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7219_NO_INVERT       0
+#define DA7219_INVERT          1
+
+/* Byte related defines */
+#define DA7219_BYTE_SHIFT      8
+#define DA7219_BYTE_MASK       0xFF
+
+/* PLL Output Frequencies */
+#define DA7219_PLL_FREQ_OUT_90316      90316800
+#define DA7219_PLL_FREQ_OUT_98304      98304000
+
+/* PLL Frequency Dividers */
+#define DA7219_PLL_INDIV_2_5_MHZ_VAL   1
+#define DA7219_PLL_INDIV_5_10_MHZ_VAL  2
+#define DA7219_PLL_INDIV_10_20_MHZ_VAL 4
+#define DA7219_PLL_INDIV_20_40_MHZ_VAL 8
+#define DA7219_PLL_INDIV_40_54_MHZ_VAL 16
+
+/* SRM */
+#define DA7219_SRM_CHECK_RETRIES       8
+
+enum da7219_clk_src {
+       DA7219_CLKSRC_MCLK = 0,
+       DA7219_CLKSRC_MCLK_SQR,
+};
+
+enum da7219_sys_clk {
+       DA7219_SYSCLK_MCLK = 0,
+       DA7219_SYSCLK_PLL,
+       DA7219_SYSCLK_PLL_SRM,
+       DA7219_SYSCLK_PLL_32KHZ
+};
+
+/* Regulators */
+enum da7219_supplies {
+       DA7219_SUPPLY_VDD = 0,
+       DA7219_SUPPLY_VDDMIC,
+       DA7219_SUPPLY_VDDIO,
+       DA7219_NUM_SUPPLIES,
+};
+
+struct da7219_aad_priv;
+
+/* Private data */
+struct da7219_priv {
+       struct da7219_aad_priv *aad;
+       struct da7219_pdata *pdata;
+
+       struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES];
+       struct regmap *regmap;
+       struct mutex lock;
+
+       struct clk *mclk;
+       unsigned int mclk_rate;
+       int clk_src;
+
+       bool master;
+       bool alc_en;
+};
+
+#endif /* __DA7219_H */
index 6a091016e0fc767c2465cfd5c8eaf822d09d2ea3..969e337dc17c131413e43f666edd5b299fc11544 100644 (file)
@@ -129,7 +129,7 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
        int ret;
 
        if (deemph > 1)
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
deleted file mode 100644 (file)
index bd42ad3..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * ALSA SoC codec driver for HDMI audio codecs.
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#define DRV_NAME "hdmi-audio-codec"
-
-static const struct snd_soc_dapm_widget hdmi_widgets[] = {
-       SND_SOC_DAPM_INPUT("RX"),
-       SND_SOC_DAPM_OUTPUT("TX"),
-};
-
-static const struct snd_soc_dapm_route hdmi_routes[] = {
-       { "Capture", NULL, "RX" },
-       { "TX", NULL, "Playback" },
-};
-
-static struct snd_soc_dai_driver hdmi_codec_dai = {
-       .name = "hdmi-hifi",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = SNDRV_PCM_RATE_32000 |
-                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-                       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-                       SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |
-                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
-               .sig_bits = 24,
-       },
-       .capture = {
-               .stream_name = "Capture",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_32000 |
-                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-                       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-                       SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |
-                       SNDRV_PCM_FMTBIT_S24_LE,
-       },
-
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id hdmi_audio_codec_ids[] = {
-       { .compatible = "linux,hdmi-audio", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
-#endif
-
-static struct snd_soc_codec_driver hdmi_codec = {
-       .dapm_widgets = hdmi_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
-       .dapm_routes = hdmi_routes,
-       .num_dapm_routes = ARRAY_SIZE(hdmi_routes),
-       .ignore_pmdown_time = true,
-};
-
-static int hdmi_codec_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_codec(&pdev->dev, &hdmi_codec,
-                       &hdmi_codec_dai, 1);
-}
-
-static int hdmi_codec_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_codec(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver hdmi_codec_driver = {
-       .driver         = {
-               .name   = DRV_NAME,
-               .of_match_table = of_match_ptr(hdmi_audio_codec_ids),
-       },
-
-       .probe          = hdmi_codec_probe,
-       .remove         = hdmi_codec_remove,
-};
-
-module_platform_driver(hdmi_codec_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("ASoC generic HDMI codec driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
new file mode 100644 (file)
index 0000000..7fc7b4e
--- /dev/null
@@ -0,0 +1,1309 @@
+/*
+ * Nuvoton NAU8825 audio codec driver
+ *
+ * Copyright 2015 Google Chromium project.
+ *  Author: Anatol Pomozov <anatol@chromium.org>
+ * Copyright 2015 Nuvoton Technology Corp.
+ *  Co-author: Meng-Huang Kuo <mhkuo@nuvoton.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/acpi.h>
+#include <linux/math64.h>
+
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+
+#include "nau8825.h"
+
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 100000000
+#define NAU_FVCO_MIN 90000000
+
+struct nau8825_fll {
+       int mclk_src;
+       int ratio;
+       int fll_frac;
+       int fll_int;
+       int clk_ref_div;
+};
+
+struct nau8825_fll_attr {
+       unsigned int param;
+       unsigned int val;
+};
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8825_fll_attr mclk_src_scaling[] = {
+       { 1, 0x0 },
+       { 2, 0x2 },
+       { 4, 0x3 },
+       { 8, 0x4 },
+       { 16, 0x5 },
+       { 32, 0x6 },
+       { 3, 0x7 },
+       { 6, 0xa },
+       { 12, 0xb },
+       { 24, 0xc },
+       { 48, 0xd },
+       { 96, 0xe },
+       { 5, 0xf },
+};
+
+/* ratio for input clk freq */
+static const struct nau8825_fll_attr fll_ratio[] = {
+       { 512000, 0x01 },
+       { 256000, 0x02 },
+       { 128000, 0x04 },
+       { 64000, 0x08 },
+       { 32000, 0x10 },
+       { 8000, 0x20 },
+       { 4000, 0x40 },
+};
+
+static const struct nau8825_fll_attr fll_pre_scalar[] = {
+       { 1, 0x0 },
+       { 2, 0x1 },
+       { 4, 0x2 },
+       { 8, 0x3 },
+};
+
+static const struct reg_default nau8825_reg_defaults[] = {
+       { NAU8825_REG_ENA_CTRL, 0x00ff },
+       { NAU8825_REG_CLK_DIVIDER, 0x0050 },
+       { NAU8825_REG_FLL1, 0x0 },
+       { NAU8825_REG_FLL2, 0x3126 },
+       { NAU8825_REG_FLL3, 0x0008 },
+       { NAU8825_REG_FLL4, 0x0010 },
+       { NAU8825_REG_FLL5, 0x0 },
+       { NAU8825_REG_FLL6, 0x6000 },
+       { NAU8825_REG_FLL_VCO_RSV, 0xf13c },
+       { NAU8825_REG_HSD_CTRL, 0x000c },
+       { NAU8825_REG_JACK_DET_CTRL, 0x0 },
+       { NAU8825_REG_INTERRUPT_MASK, 0x0 },
+       { NAU8825_REG_INTERRUPT_DIS_CTRL, 0xffff },
+       { NAU8825_REG_SAR_CTRL, 0x0015 },
+       { NAU8825_REG_KEYDET_CTRL, 0x0110 },
+       { NAU8825_REG_VDET_THRESHOLD_1, 0x0 },
+       { NAU8825_REG_VDET_THRESHOLD_2, 0x0 },
+       { NAU8825_REG_VDET_THRESHOLD_3, 0x0 },
+       { NAU8825_REG_VDET_THRESHOLD_4, 0x0 },
+       { NAU8825_REG_GPIO34_CTRL, 0x0 },
+       { NAU8825_REG_GPIO12_CTRL, 0x0 },
+       { NAU8825_REG_TDM_CTRL, 0x0 },
+       { NAU8825_REG_I2S_PCM_CTRL1, 0x000b },
+       { NAU8825_REG_I2S_PCM_CTRL2, 0x8010 },
+       { NAU8825_REG_LEFT_TIME_SLOT, 0x0 },
+       { NAU8825_REG_RIGHT_TIME_SLOT, 0x0 },
+       { NAU8825_REG_BIQ_CTRL, 0x0 },
+       { NAU8825_REG_BIQ_COF1, 0x0 },
+       { NAU8825_REG_BIQ_COF2, 0x0 },
+       { NAU8825_REG_BIQ_COF3, 0x0 },
+       { NAU8825_REG_BIQ_COF4, 0x0 },
+       { NAU8825_REG_BIQ_COF5, 0x0 },
+       { NAU8825_REG_BIQ_COF6, 0x0 },
+       { NAU8825_REG_BIQ_COF7, 0x0 },
+       { NAU8825_REG_BIQ_COF8, 0x0 },
+       { NAU8825_REG_BIQ_COF9, 0x0 },
+       { NAU8825_REG_BIQ_COF10, 0x0 },
+       { NAU8825_REG_ADC_RATE, 0x0010 },
+       { NAU8825_REG_DAC_CTRL1, 0x0001 },
+       { NAU8825_REG_DAC_CTRL2, 0x0 },
+       { NAU8825_REG_DAC_DGAIN_CTRL, 0x0 },
+       { NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf },
+       { NAU8825_REG_MUTE_CTRL, 0x0 },
+       { NAU8825_REG_HSVOL_CTRL, 0x0 },
+       { NAU8825_REG_DACL_CTRL, 0x02cf },
+       { NAU8825_REG_DACR_CTRL, 0x00cf },
+       { NAU8825_REG_ADC_DRC_KNEE_IP12, 0x1486 },
+       { NAU8825_REG_ADC_DRC_KNEE_IP34, 0x0f12 },
+       { NAU8825_REG_ADC_DRC_SLOPES, 0x25ff },
+       { NAU8825_REG_ADC_DRC_ATKDCY, 0x3457 },
+       { NAU8825_REG_DAC_DRC_KNEE_IP12, 0x1486 },
+       { NAU8825_REG_DAC_DRC_KNEE_IP34, 0x0f12 },
+       { NAU8825_REG_DAC_DRC_SLOPES, 0x25f9 },
+       { NAU8825_REG_DAC_DRC_ATKDCY, 0x3457 },
+       { NAU8825_REG_IMM_MODE_CTRL, 0x0 },
+       { NAU8825_REG_CLASSG_CTRL, 0x0 },
+       { NAU8825_REG_OPT_EFUSE_CTRL, 0x0 },
+       { NAU8825_REG_MISC_CTRL, 0x0 },
+       { NAU8825_REG_BIAS_ADJ, 0x0 },
+       { NAU8825_REG_TRIM_SETTINGS, 0x0 },
+       { NAU8825_REG_ANALOG_CONTROL_1, 0x0 },
+       { NAU8825_REG_ANALOG_CONTROL_2, 0x0 },
+       { NAU8825_REG_ANALOG_ADC_1, 0x0011 },
+       { NAU8825_REG_ANALOG_ADC_2, 0x0020 },
+       { NAU8825_REG_RDAC, 0x0008 },
+       { NAU8825_REG_MIC_BIAS, 0x0006 },
+       { NAU8825_REG_BOOST, 0x0 },
+       { NAU8825_REG_FEPGA, 0x0 },
+       { NAU8825_REG_POWER_UP_CONTROL, 0x0 },
+       { NAU8825_REG_CHARGE_PUMP, 0x0 },
+};
+
+static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case NAU8825_REG_ENA_CTRL:
+       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
+       case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL:
+       case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
+       case NAU8825_REG_ADC_DRC_KNEE_IP12 ... NAU8825_REG_ADC_DRC_ATKDCY:
+       case NAU8825_REG_DAC_DRC_KNEE_IP12 ... NAU8825_REG_DAC_DRC_ATKDCY:
+       case NAU8825_REG_IMM_MODE_CTRL ... NAU8825_REG_IMM_RMS_R:
+       case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
+       case NAU8825_REG_MISC_CTRL:
+       case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_SARDOUT_RAM_STATUS:
+       case NAU8825_REG_BIAS_ADJ:
+       case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
+       case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
+       case NAU8825_REG_BOOST ... NAU8825_REG_FEPGA:
+       case NAU8825_REG_POWER_UP_CONTROL ... NAU8825_REG_GENERAL_STATUS:
+               return true;
+       default:
+               return false;
+       }
+
+}
+
+static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case NAU8825_REG_RESET ... NAU8825_REG_ENA_CTRL:
+       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
+       case NAU8825_REG_INTERRUPT_MASK:
+       case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL:
+       case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
+       case NAU8825_REG_ADC_DRC_KNEE_IP12 ... NAU8825_REG_ADC_DRC_ATKDCY:
+       case NAU8825_REG_DAC_DRC_KNEE_IP12 ... NAU8825_REG_DAC_DRC_ATKDCY:
+       case NAU8825_REG_IMM_MODE_CTRL:
+       case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
+       case NAU8825_REG_MISC_CTRL:
+       case NAU8825_REG_BIAS_ADJ:
+       case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
+       case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
+       case NAU8825_REG_BOOST ... NAU8825_REG_FEPGA:
+       case NAU8825_REG_POWER_UP_CONTROL ... NAU8825_REG_CHARGE_PUMP:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case NAU8825_REG_RESET:
+       case NAU8825_REG_IRQ_STATUS:
+       case NAU8825_REG_INT_CLR_KEY_STATUS:
+       case NAU8825_REG_IMM_RMS_L:
+       case NAU8825_REG_IMM_RMS_R:
+       case NAU8825_REG_I2C_DEVICE_ID:
+       case NAU8825_REG_SARDOUT_RAM_STATUS:
+       case NAU8825_REG_CHARGE_PUMP_INPUT_READ:
+       case NAU8825_REG_GENERAL_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Prevent startup click by letting charge pump to ramp up */
+               msleep(10);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const char * const nau8825_adc_decimation[] = {
+       "32", "64", "128", "256"
+};
+
+static const struct soc_enum nau8825_adc_decimation_enum =
+       SOC_ENUM_SINGLE(NAU8825_REG_ADC_RATE, NAU8825_ADC_SYNC_DOWN_SFT,
+               ARRAY_SIZE(nau8825_adc_decimation), nau8825_adc_decimation);
+
+static const char * const nau8825_dac_oversampl[] = {
+       "64", "256", "128", "", "32"
+};
+
+static const struct soc_enum nau8825_dac_oversampl_enum =
+       SOC_ENUM_SINGLE(NAU8825_REG_DAC_CTRL1, NAU8825_DAC_OVERSAMPLE_SFT,
+               ARRAY_SIZE(nau8825_dac_oversampl), nau8825_dac_oversampl);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adc_vol_tlv, -10300, 2400);
+static const DECLARE_TLV_DB_MINMAX_MUTE(sidetone_vol_tlv, -4200, 0);
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -5400, 0);
+static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
+static const DECLARE_TLV_DB_MINMAX_MUTE(crosstalk_vol_tlv, -9600, 2400);
+
+static const struct snd_kcontrol_new nau8825_controls[] = {
+       SOC_SINGLE_TLV("Mic Volume", NAU8825_REG_ADC_DGAIN_CTRL,
+               0, 0xff, 0, adc_vol_tlv),
+       SOC_DOUBLE_TLV("Headphone Bypass Volume", NAU8825_REG_ADC_DGAIN_CTRL,
+               12, 8, 0x0f, 0, sidetone_vol_tlv),
+       SOC_DOUBLE_TLV("Headphone Volume", NAU8825_REG_HSVOL_CTRL,
+               6, 0, 0x3f, 1, dac_vol_tlv),
+       SOC_SINGLE_TLV("Frontend PGA Volume", NAU8825_REG_POWER_UP_CONTROL,
+               8, 37, 0, fepga_gain_tlv),
+       SOC_DOUBLE_TLV("Headphone Crosstalk Volume", NAU8825_REG_DAC_DGAIN_CTRL,
+               0, 8, 0xff, 0, crosstalk_vol_tlv),
+
+       SOC_ENUM("ADC Decimation Rate", nau8825_adc_decimation_enum),
+       SOC_ENUM("DAC Oversampling Rate", nau8825_dac_oversampl_enum),
+};
+
+/* DAC Mux 0x33[9] and 0x34[9] */
+static const char * const nau8825_dac_src[] = {
+       "DACL", "DACR",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       nau8825_dacl_enum, NAU8825_REG_DACL_CTRL,
+       NAU8825_DACL_CH_SEL_SFT, nau8825_dac_src);
+
+static SOC_ENUM_SINGLE_DECL(
+       nau8825_dacr_enum, NAU8825_REG_DACR_CTRL,
+       NAU8825_DACR_CH_SEL_SFT, nau8825_dac_src);
+
+static const struct snd_kcontrol_new nau8825_dacl_mux =
+       SOC_DAPM_ENUM("DACL Source", nau8825_dacl_enum);
+
+static const struct snd_kcontrol_new nau8825_dacr_mux =
+       SOC_DAPM_ENUM("DACR Source", nau8825_dacr_enum);
+
+
+static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, NAU8825_REG_I2S_PCM_CTRL2,
+               15, 1),
+
+       SND_SOC_DAPM_INPUT("MIC"),
+       SND_SOC_DAPM_MICBIAS("MICBIAS", NAU8825_REG_MIC_BIAS, 8, 0),
+
+       SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0,
+               NULL, 0),
+
+       SND_SOC_DAPM_ADC("ADC", NULL, NAU8825_REG_ENA_CTRL, 8, 0),
+       SND_SOC_DAPM_SUPPLY("ADC Clock", NAU8825_REG_ENA_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL,
+               0),
+
+       /* ADC for button press detection */
+       SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL,
+               NAU8825_SAR_ADC_EN_SFT, 0),
+
+       SND_SOC_DAPM_DAC("ADACL", NULL, NAU8825_REG_RDAC, 12, 0),
+       SND_SOC_DAPM_DAC("ADACR", NULL, NAU8825_REG_RDAC, 13, 0),
+       SND_SOC_DAPM_SUPPLY("ADACL Clock", NAU8825_REG_RDAC, 8, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADACR Clock", NAU8825_REG_RDAC, 9, 0, NULL, 0),
+
+       SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL,
+               NAU8825_ENABLE_DACR_SFT, 0),
+       SND_SOC_DAPM_DAC("DDACL", NULL, NAU8825_REG_ENA_CTRL,
+               NAU8825_ENABLE_DACL_SFT, 0),
+       SND_SOC_DAPM_SUPPLY("DDAC Clock", NAU8825_REG_ENA_CTRL, 6, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux),
+       SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux),
+
+       SND_SOC_DAPM_PGA("HP amp L", NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP amp R", NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("HP amp power", NAU8825_REG_CLASSG_CTRL, 0, 0, NULL,
+               0),
+
+       SND_SOC_DAPM_SUPPLY("Charge Pump", NAU8825_REG_CHARGE_PUMP, 5, 0,
+               nau8825_pump_event, SND_SOC_DAPM_POST_PMU),
+
+       SND_SOC_DAPM_PGA("Output Driver R Stage 1",
+               NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Output Driver L Stage 1",
+               NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Output Driver R Stage 2",
+               NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Output Driver L Stage 2",
+               NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 1,
+               NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 1,
+               NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA_S("Output DACL", 2, NAU8825_REG_CHARGE_PUMP, 8, 1, NULL, 0),
+       SND_SOC_DAPM_PGA_S("Output DACR", 2, NAU8825_REG_CHARGE_PUMP, 9, 1, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
+       {"Frontend PGA", NULL, "MIC"},
+       {"ADC", NULL, "Frontend PGA"},
+       {"ADC", NULL, "ADC Clock"},
+       {"ADC", NULL, "ADC Power"},
+       {"AIFTX", NULL, "ADC"},
+
+       {"DDACL", NULL, "Playback"},
+       {"DDACR", NULL, "Playback"},
+       {"DDACL", NULL, "DDAC Clock"},
+       {"DDACR", NULL, "DDAC Clock"},
+       {"DACL Mux", "DACL", "DDACL"},
+       {"DACL Mux", "DACR", "DDACR"},
+       {"DACR Mux", "DACL", "DDACL"},
+       {"DACR Mux", "DACR", "DDACR"},
+       {"HP amp L", NULL, "DACL Mux"},
+       {"HP amp R", NULL, "DACR Mux"},
+       {"HP amp L", NULL, "HP amp power"},
+       {"HP amp R", NULL, "HP amp power"},
+       {"ADACL", NULL, "HP amp L"},
+       {"ADACR", NULL, "HP amp R"},
+       {"ADACL", NULL, "ADACL Clock"},
+       {"ADACR", NULL, "ADACR Clock"},
+       {"Output Driver L Stage 1", NULL, "ADACL"},
+       {"Output Driver R Stage 1", NULL, "ADACR"},
+       {"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"},
+       {"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"},
+       {"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"},
+       {"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"},
+       {"Output DACL", NULL, "Output Driver L Stage 3"},
+       {"Output DACR", NULL, "Output Driver R Stage 3"},
+       {"HPOL", NULL, "Output DACL"},
+       {"HPOR", NULL, "Output DACR"},
+       {"HPOL", NULL, "Charge Pump"},
+       {"HPOR", NULL, "Charge Pump"},
+};
+
+static int nau8825_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0;
+
+       switch (params_width(params)) {
+       case 16:
+               val_len |= NAU8825_I2S_DL_16;
+               break;
+       case 20:
+               val_len |= NAU8825_I2S_DL_20;
+               break;
+       case 24:
+               val_len |= NAU8825_I2S_DL_24;
+               break;
+       case 32:
+               val_len |= NAU8825_I2S_DL_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
+               NAU8825_I2S_DL_MASK, val_len);
+
+       return 0;
+}
+
+static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               ctrl2_val |= NAU8825_I2S_MS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               ctrl1_val |= NAU8825_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ctrl1_val |= NAU8825_I2S_DF_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctrl1_val |= NAU8825_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ctrl1_val |= NAU8825_I2S_DF_RIGTH;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               ctrl1_val |= NAU8825_I2S_DF_PCM_AB;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctrl1_val |= NAU8825_I2S_DF_PCM_AB;
+               ctrl1_val |= NAU8825_I2S_PCMB_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
+               NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK |
+               NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK,
+               ctrl1_val);
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+               NAU8825_I2S_MS_MASK, ctrl2_val);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops nau8825_dai_ops = {
+       .hw_params      = nau8825_hw_params,
+       .set_fmt        = nau8825_set_dai_fmt,
+};
+
+#define NAU8825_RATES  SNDRV_PCM_RATE_8000_192000
+#define NAU8825_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8825_dai = {
+       .name = "nau8825-hifi",
+       .playback = {
+               .stream_name     = "Playback",
+               .channels_min    = 1,
+               .channels_max    = 2,
+               .rates           = NAU8825_RATES,
+               .formats         = NAU8825_FORMATS,
+       },
+       .capture = {
+               .stream_name     = "Capture",
+               .channels_min    = 1,
+               .channels_max    = 1,
+               .rates           = NAU8825_RATES,
+               .formats         = NAU8825_FORMATS,
+       },
+       .ops = &nau8825_dai_ops,
+};
+
+/**
+ * nau8825_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component:  component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events will be routed to the given jack.  Jack can be null to stop
+ * reporting.
+ */
+int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack)
+{
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       struct regmap *regmap = nau8825->regmap;
+
+       nau8825->jack = jack;
+
+       /* Ground HP Outputs[1:0], needed for headset auto detection
+        * Enable Automatic Mic/Gnd switching reading on insert interrupt[6]
+        */
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+               NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L,
+               NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+
+       regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+               NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_EJECT_EN, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nau8825_enable_jack_detect);
+
+
+static bool nau8825_is_jack_inserted(struct regmap *regmap)
+{
+       int status;
+
+       regmap_read(regmap, NAU8825_REG_I2C_DEVICE_ID, &status);
+       return !(status & NAU8825_GPIO2JD1);
+}
+
+static void nau8825_restart_jack_detection(struct regmap *regmap)
+{
+       /* this will restart the entire jack detection process including MIC/GND
+        * switching and create interrupts. We have to go from 0 to 1 and back
+        * to 0 to restart.
+        */
+       regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+               NAU8825_JACK_DET_RESTART, NAU8825_JACK_DET_RESTART);
+       regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+               NAU8825_JACK_DET_RESTART, 0);
+}
+
+static void nau8825_eject_jack(struct nau8825 *nau8825)
+{
+       struct snd_soc_dapm_context *dapm = nau8825->dapm;
+       struct regmap *regmap = nau8825->regmap;
+
+       snd_soc_dapm_disable_pin(dapm, "SAR");
+       snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+       /* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+               NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+       /* ground HPL/HPR, MICGRND1/2 */
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0xf, 0xf);
+
+       snd_soc_dapm_sync(dapm);
+}
+
+static int nau8825_button_decode(int value)
+{
+       int buttons = 0;
+
+       /* The chip supports up to 8 buttons, but ALSA defines only 6 buttons */
+       if (value & BIT(0))
+               buttons |= SND_JACK_BTN_0;
+       if (value & BIT(1))
+               buttons |= SND_JACK_BTN_1;
+       if (value & BIT(2))
+               buttons |= SND_JACK_BTN_2;
+       if (value & BIT(3))
+               buttons |= SND_JACK_BTN_3;
+       if (value & BIT(4))
+               buttons |= SND_JACK_BTN_4;
+       if (value & BIT(5))
+               buttons |= SND_JACK_BTN_5;
+
+       return buttons;
+}
+
+static int nau8825_jack_insert(struct nau8825 *nau8825)
+{
+       struct regmap *regmap = nau8825->regmap;
+       struct snd_soc_dapm_context *dapm = nau8825->dapm;
+       int jack_status_reg, mic_detected;
+       int type = 0;
+
+       regmap_read(regmap, NAU8825_REG_GENERAL_STATUS, &jack_status_reg);
+       mic_detected = (jack_status_reg >> 10) & 3;
+
+       switch (mic_detected) {
+       case 0:
+               /* no mic */
+               type = SND_JACK_HEADPHONE;
+               break;
+       case 1:
+               dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n");
+               type = SND_JACK_HEADSET;
+
+               /* Unground MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 3 << 2,
+                       1 << 2);
+               /* Attach 2kOhm Resistor from MICBIAS to MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                       NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                       NAU8825_MICBIAS_JKR2);
+               /* Attach SARADC to MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                       NAU8825_SAR_INPUT_MASK,
+                       NAU8825_SAR_INPUT_JKR2);
+
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+               snd_soc_dapm_force_enable_pin(dapm, "SAR");
+               snd_soc_dapm_sync(dapm);
+               break;
+       case 2:
+       case 3:
+               dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
+               type = SND_JACK_HEADSET;
+
+               /* Unground MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 3 << 2,
+                       2 << 2);
+               /* Attach 2kOhm Resistor from MICBIAS to MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                       NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                       NAU8825_MICBIAS_JKSLV);
+               /* Attach SARADC to MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                       NAU8825_SAR_INPUT_MASK,
+                       NAU8825_SAR_INPUT_JKSLV);
+
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+               snd_soc_dapm_force_enable_pin(dapm, "SAR");
+               snd_soc_dapm_sync(dapm);
+               break;
+       }
+
+       if (type & SND_JACK_HEADPHONE) {
+               /* Unground HPL/R */
+               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0x3, 0);
+       }
+
+       return type;
+}
+
+#define NAU8825_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+               SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+static irqreturn_t nau8825_interrupt(int irq, void *data)
+{
+       struct nau8825 *nau8825 = (struct nau8825 *)data;
+       struct regmap *regmap = nau8825->regmap;
+       int active_irq, clear_irq = 0, event = 0, event_mask = 0;
+
+       regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq);
+
+       if ((active_irq & NAU8825_JACK_EJECTION_IRQ_MASK) ==
+               NAU8825_JACK_EJECTION_DETECTED) {
+
+               nau8825_eject_jack(nau8825);
+               event_mask |= SND_JACK_HEADSET;
+               clear_irq = NAU8825_JACK_EJECTION_IRQ_MASK;
+       } else if (active_irq & NAU8825_KEY_SHORT_PRESS_IRQ) {
+               int key_status;
+
+               regmap_read(regmap, NAU8825_REG_INT_CLR_KEY_STATUS,
+                       &key_status);
+
+               /* upper 8 bits of the register are for short pressed keys,
+                * lower 8 bits - for long pressed buttons
+                */
+               nau8825->button_pressed = nau8825_button_decode(
+                       key_status >> 8);
+
+               event |= nau8825->button_pressed;
+               event_mask |= NAU8825_BUTTONS;
+               clear_irq = NAU8825_KEY_SHORT_PRESS_IRQ;
+       } else if (active_irq & NAU8825_KEY_RELEASE_IRQ) {
+               event_mask = NAU8825_BUTTONS;
+               clear_irq = NAU8825_KEY_RELEASE_IRQ;
+       } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
+               if (nau8825_is_jack_inserted(regmap)) {
+                       event |= nau8825_jack_insert(nau8825);
+               } else {
+                       dev_warn(nau8825->dev, "Headset completion IRQ fired but no headset connected\n");
+                       nau8825_eject_jack(nau8825);
+               }
+
+               event_mask |= SND_JACK_HEADSET;
+               clear_irq = NAU8825_HEADSET_COMPLETION_IRQ;
+       }
+
+       if (!clear_irq)
+               clear_irq = active_irq;
+       /* clears the rightmost interruption */
+       regmap_write(regmap, NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq);
+
+       if (event_mask)
+               snd_soc_jack_report(nau8825->jack, event, event_mask);
+
+       return IRQ_HANDLED;
+}
+
+static void nau8825_setup_buttons(struct nau8825 *nau8825)
+{
+       struct regmap *regmap = nau8825->regmap;
+
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+               NAU8825_SAR_TRACKING_GAIN_MASK,
+               nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+               NAU8825_SAR_COMPARE_TIME_MASK,
+               nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+               NAU8825_SAR_SAMPLING_TIME_MASK,
+               nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT);
+
+       regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+               NAU8825_KEYDET_LEVELS_NR_MASK,
+               (nau8825->sar_threshold_num - 1) << NAU8825_KEYDET_LEVELS_NR_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+               NAU8825_KEYDET_HYSTERESIS_MASK,
+               nau8825->sar_hysteresis << NAU8825_KEYDET_HYSTERESIS_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+               NAU8825_KEYDET_SHORTKEY_DEBOUNCE_MASK,
+               nau8825->key_debounce << NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT);
+
+       regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_1,
+               (nau8825->sar_threshold[0] << 8) | nau8825->sar_threshold[1]);
+       regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_2,
+               (nau8825->sar_threshold[2] << 8) | nau8825->sar_threshold[3]);
+       regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_3,
+               (nau8825->sar_threshold[4] << 8) | nau8825->sar_threshold[5]);
+       regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_4,
+               (nau8825->sar_threshold[6] << 8) | nau8825->sar_threshold[7]);
+
+       /* Enable short press and release interruptions */
+       regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+               NAU8825_IRQ_KEY_SHORT_PRESS_EN | NAU8825_IRQ_KEY_RELEASE_EN,
+               0);
+}
+
+static void nau8825_init_regs(struct nau8825 *nau8825)
+{
+       struct regmap *regmap = nau8825->regmap;
+
+       /* Enable Bias/Vmid */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+               NAU8825_BIAS_VMID, NAU8825_BIAS_VMID);
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+               NAU8825_GLOBAL_BIAS_EN, NAU8825_GLOBAL_BIAS_EN);
+
+       /* VMID Tieoff */
+       regmap_update_bits(regmap, NAU8825_REG_BIAS_ADJ,
+               NAU8825_BIAS_VMID_SEL_MASK,
+               nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT);
+       /* Disable Boost Driver, Automatic Short circuit protection enable */
+       regmap_update_bits(regmap, NAU8825_REG_BOOST,
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
+               NAU8825_SHORT_SHUTDOWN_EN,
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
+               NAU8825_SHORT_SHUTDOWN_EN);
+
+       regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+               NAU8825_JKDET_OUTPUT_EN,
+               nau8825->jkdet_enable ? 0 : NAU8825_JKDET_OUTPUT_EN);
+       regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+               NAU8825_JKDET_PULL_EN,
+               nau8825->jkdet_pull_enable ? 0 : NAU8825_JKDET_PULL_EN);
+       regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+               NAU8825_JKDET_PULL_UP,
+               nau8825->jkdet_pull_up ? NAU8825_JKDET_PULL_UP : 0);
+       regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+               NAU8825_JACK_POLARITY,
+               /* jkdet_polarity - 1  is for active-low */
+               nau8825->jkdet_polarity ? 0 : NAU8825_JACK_POLARITY);
+
+       regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+               NAU8825_JACK_INSERT_DEBOUNCE_MASK,
+               nau8825->jack_insert_debounce << NAU8825_JACK_INSERT_DEBOUNCE_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+               NAU8825_JACK_EJECT_DEBOUNCE_MASK,
+               nau8825->jack_eject_debounce << NAU8825_JACK_EJECT_DEBOUNCE_SFT);
+
+       /* Mask unneeded IRQs: 1 - disable, 0 - enable */
+       regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, 0x7ff, 0x7ff);
+
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+               NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage);
+
+       if (nau8825->sar_threshold_num)
+               nau8825_setup_buttons(nau8825);
+
+       /* Default oversampling/decimations settings are unusable
+        * (audible hiss). Set it to something better.
+        */
+       regmap_update_bits(regmap, NAU8825_REG_ADC_RATE,
+               NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128);
+       regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
+               NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128);
+}
+
+static const struct regmap_config nau8825_regmap_config = {
+       .val_bits = 16,
+       .reg_bits = 16,
+
+       .max_register = NAU8825_REG_MAX,
+       .readable_reg = nau8825_readable_reg,
+       .writeable_reg = nau8825_writeable_reg,
+       .volatile_reg = nau8825_volatile_reg,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = nau8825_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(nau8825_reg_defaults),
+};
+
+static int nau8825_codec_probe(struct snd_soc_codec *codec)
+{
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+       nau8825->dapm = dapm;
+
+       /* The interrupt clock is gated by x1[10:8],
+        * one of them needs to be enabled all the time for
+        * interrupts to happen.
+        */
+       snd_soc_dapm_force_enable_pin(dapm, "DDACR");
+       snd_soc_dapm_sync(dapm);
+
+       /* Unmask interruptions. Handler uses dapm object so we can enable
+        * interruptions only after dapm is fully initialized.
+        */
+       regmap_write(nau8825->regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, 0);
+       nau8825_restart_jack_detection(nau8825->regmap);
+
+       return 0;
+}
+
+/**
+ * nau8825_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
+               struct nau8825_fll *fll_param)
+{
+       u64 fvco;
+       unsigned int fref, i;
+
+       /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+        * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+        * FREF = freq_in / NAU8825_FLL_REF_DIV_MASK
+        */
+       for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+               fref = fll_in / fll_pre_scalar[i].param;
+               if (fref <= NAU_FREF_MAX)
+                       break;
+       }
+       if (i == ARRAY_SIZE(fll_pre_scalar))
+               return -EINVAL;
+       fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+       /* Choose the FLL ratio based on FREF */
+       for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+               if (fref >= fll_ratio[i].param)
+                       break;
+       }
+       if (i == ARRAY_SIZE(fll_ratio))
+               return -EINVAL;
+       fll_param->ratio = fll_ratio[i].val;
+
+       /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+        * FDCO must be within the 90MHz - 100MHz or the FFL cannot be
+        * guaranteed across the full range of operation.
+        * FDCO = freq_out * 2 * mclk_src_scaling
+        */
+       for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+               fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+               if (NAU_FVCO_MIN < fvco && fvco < NAU_FVCO_MAX)
+                       break;
+       }
+       if (i == ARRAY_SIZE(mclk_src_scaling))
+               return -EINVAL;
+       fll_param->mclk_src = mclk_src_scaling[i].val;
+
+       /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+        * input based on FDCO, FREF and FLL ratio.
+        */
+       fvco = div_u64(fvco << 16, fref * fll_param->ratio);
+       fll_param->fll_int = (fvco >> 16) & 0x3FF;
+       fll_param->fll_frac = fvco & 0xFFFF;
+       return 0;
+}
+
+static void nau8825_fll_apply(struct nau8825 *nau8825,
+               struct nau8825_fll *fll_param)
+{
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+               NAU8825_CLK_MCLK_SRC_MASK, fll_param->mclk_src);
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
+                       NAU8825_FLL_RATIO_MASK, fll_param->ratio);
+       /* FLL 16-bit fractional input */
+       regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
+       /* FLL 10-bit integer input */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL3,
+                       NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
+       /* FLL pre-scaler */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4,
+                       NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div);
+       /* select divided VCO input */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
+                       NAU8825_FLL_FILTER_SW_MASK, 0x0000);
+       /* FLL sigma delta modulator enable */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
+                       NAU8825_SDM_EN_MASK, NAU8825_SDM_EN);
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8825_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+               unsigned int freq_in, unsigned int freq_out)
+{
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       struct nau8825_fll fll_param;
+       int ret, fs;
+
+       fs = freq_out / 256;
+       ret = nau8825_calc_fll_param(freq_in, fs, &fll_param);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupported input clock %d\n", freq_in);
+               return ret;
+       }
+       dev_dbg(codec->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+               fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+               fll_param.fll_int, fll_param.clk_ref_div);
+
+       nau8825_fll_apply(nau8825, &fll_param);
+       mdelay(2);
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+                       NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
+       return 0;
+}
+
+static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
+       unsigned int freq)
+{
+       struct regmap *regmap = nau8825->regmap;
+       int ret;
+
+       switch (clk_id) {
+       case NAU8825_CLK_MCLK:
+               regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+                       NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK);
+               regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0);
+
+               /* We selected MCLK source but the clock itself managed externally */
+               if (!nau8825->mclk)
+                       break;
+
+               if (!nau8825->mclk_freq) {
+                       ret = clk_prepare_enable(nau8825->mclk);
+                       if (ret) {
+                               dev_err(nau8825->dev, "Unable to prepare codec mclk\n");
+                               return ret;
+                       }
+               }
+
+               if (nau8825->mclk_freq != freq) {
+                       nau8825->mclk_freq = freq;
+
+                       freq = clk_round_rate(nau8825->mclk, freq);
+                       ret = clk_set_rate(nau8825->mclk, freq);
+                       if (ret) {
+                               dev_err(nau8825->dev, "Unable to set mclk rate\n");
+                               return ret;
+                       }
+               }
+
+               break;
+       case NAU8825_CLK_INTERNAL:
+               regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN,
+                       NAU8825_DCO_EN);
+               regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+                       NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
+
+               if (nau8825->mclk_freq) {
+                       clk_disable_unprepare(nau8825->mclk);
+                       nau8825->mclk_freq = 0;
+               }
+
+               break;
+       default:
+               dev_err(nau8825->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+
+       dev_dbg(nau8825->dev, "Sysclk is %dHz and clock id is %d\n", freq,
+               clk_id);
+       return 0;
+}
+
+static int nau8825_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+       int source, unsigned int freq, int dir)
+{
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+
+       return nau8825_configure_sysclk(nau8825, clk_id, freq);
+}
+
+static int nau8825_set_bias_level(struct snd_soc_codec *codec,
+                                  enum snd_soc_bias_level level)
+{
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       if (nau8825->mclk_freq) {
+                               ret = clk_prepare_enable(nau8825->mclk);
+                               if (ret) {
+                                       dev_err(nau8825->dev, "Unable to prepare codec mclk\n");
+                                       return ret;
+                               }
+                       }
+
+                       ret = regcache_sync(nau8825->regmap);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+               }
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               if (nau8825->mclk_freq)
+                       clk_disable_unprepare(nau8825->mclk);
+
+               regcache_mark_dirty(nau8825->regmap);
+               break;
+       }
+       return 0;
+}
+
+static struct snd_soc_codec_driver nau8825_codec_driver = {
+       .probe = nau8825_codec_probe,
+       .set_sysclk = nau8825_set_sysclk,
+       .set_pll = nau8825_set_pll,
+       .set_bias_level = nau8825_set_bias_level,
+       .suspend_bias_off = true,
+
+       .controls = nau8825_controls,
+       .num_controls = ARRAY_SIZE(nau8825_controls),
+       .dapm_widgets = nau8825_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(nau8825_dapm_widgets),
+       .dapm_routes = nau8825_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(nau8825_dapm_routes),
+};
+
+static void nau8825_reset_chip(struct regmap *regmap)
+{
+       regmap_write(regmap, NAU8825_REG_RESET, 0x00);
+       regmap_write(regmap, NAU8825_REG_RESET, 0x00);
+}
+
+static void nau8825_print_device_properties(struct nau8825 *nau8825)
+{
+       int i;
+       struct device *dev = nau8825->dev;
+
+       dev_dbg(dev, "jkdet-enable:         %d\n", nau8825->jkdet_enable);
+       dev_dbg(dev, "jkdet-pull-enable:    %d\n", nau8825->jkdet_pull_enable);
+       dev_dbg(dev, "jkdet-pull-up:        %d\n", nau8825->jkdet_pull_up);
+       dev_dbg(dev, "jkdet-polarity:       %d\n", nau8825->jkdet_polarity);
+       dev_dbg(dev, "micbias-voltage:      %d\n", nau8825->micbias_voltage);
+       dev_dbg(dev, "vref-impedance:       %d\n", nau8825->vref_impedance);
+
+       dev_dbg(dev, "sar-threshold-num:    %d\n", nau8825->sar_threshold_num);
+       for (i = 0; i < nau8825->sar_threshold_num; i++)
+               dev_dbg(dev, "sar-threshold[%d]=%d\n", i,
+                               nau8825->sar_threshold[i]);
+
+       dev_dbg(dev, "sar-hysteresis:       %d\n", nau8825->sar_hysteresis);
+       dev_dbg(dev, "sar-voltage:          %d\n", nau8825->sar_voltage);
+       dev_dbg(dev, "sar-compare-time:     %d\n", nau8825->sar_compare_time);
+       dev_dbg(dev, "sar-sampling-time:    %d\n", nau8825->sar_sampling_time);
+       dev_dbg(dev, "short-key-debounce:   %d\n", nau8825->key_debounce);
+       dev_dbg(dev, "jack-insert-debounce: %d\n",
+                       nau8825->jack_insert_debounce);
+       dev_dbg(dev, "jack-eject-debounce:  %d\n",
+                       nau8825->jack_eject_debounce);
+}
+
+static int nau8825_read_device_properties(struct device *dev,
+       struct nau8825 *nau8825) {
+
+       nau8825->jkdet_enable = device_property_read_bool(dev,
+               "nuvoton,jkdet-enable");
+       nau8825->jkdet_pull_enable = device_property_read_bool(dev,
+               "nuvoton,jkdet-pull-enable");
+       nau8825->jkdet_pull_up = device_property_read_bool(dev,
+               "nuvoton,jkdet-pull-up");
+       device_property_read_u32(dev, "nuvoton,jkdet-polarity",
+               &nau8825->jkdet_polarity);
+       device_property_read_u32(dev, "nuvoton,micbias-voltage",
+               &nau8825->micbias_voltage);
+       device_property_read_u32(dev, "nuvoton,vref-impedance",
+               &nau8825->vref_impedance);
+       device_property_read_u32(dev, "nuvoton,sar-threshold-num",
+               &nau8825->sar_threshold_num);
+       device_property_read_u32_array(dev, "nuvoton,sar-threshold",
+               nau8825->sar_threshold, nau8825->sar_threshold_num);
+       device_property_read_u32(dev, "nuvoton,sar-hysteresis",
+               &nau8825->sar_hysteresis);
+       device_property_read_u32(dev, "nuvoton,sar-voltage",
+               &nau8825->sar_voltage);
+       device_property_read_u32(dev, "nuvoton,sar-compare-time",
+               &nau8825->sar_compare_time);
+       device_property_read_u32(dev, "nuvoton,sar-sampling-time",
+               &nau8825->sar_sampling_time);
+       device_property_read_u32(dev, "nuvoton,short-key-debounce",
+               &nau8825->key_debounce);
+       device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
+               &nau8825->jack_insert_debounce);
+       device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
+               &nau8825->jack_eject_debounce);
+
+       nau8825->mclk = devm_clk_get(dev, "mclk");
+       if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (PTR_ERR(nau8825->mclk) == -ENOENT) {
+               /* The MCLK is managed externally or not used at all */
+               nau8825->mclk = NULL;
+               dev_info(dev, "No 'mclk' clock found, assume MCLK is managed externally");
+       } else if (IS_ERR(nau8825->mclk)) {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int nau8825_setup_irq(struct nau8825 *nau8825)
+{
+       struct regmap *regmap = nau8825->regmap;
+       int ret;
+
+       /* IRQ Output Enable */
+       regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+               NAU8825_IRQ_OUTPUT_EN, NAU8825_IRQ_OUTPUT_EN);
+
+       /* Enable internal VCO needed for interruptions */
+       nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+
+       /* Enable DDACR needed for interrupts
+        * It is the same as force_enable_pin("DDACR") we do later
+        */
+       regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
+               NAU8825_ENABLE_DACR, NAU8825_ENABLE_DACR);
+
+       /* Chip needs one FSCLK cycle in order to generate interrupts,
+        * as we cannot guarantee one will be provided by the system. Turning
+        * master mode on then off enables us to generate that FSCLK cycle
+        * with a minimum of contention on the clock bus.
+        */
+       regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2,
+               NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER);
+       regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2,
+               NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE);
+
+       ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL,
+               nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+               "nau8825", nau8825);
+
+       if (ret) {
+               dev_err(nau8825->dev, "Cannot request irq %d (%d)\n",
+                       nau8825->irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int nau8825_i2c_probe(struct i2c_client *i2c,
+       const struct i2c_device_id *id)
+{
+       struct device *dev = &i2c->dev;
+       struct nau8825 *nau8825 = dev_get_platdata(&i2c->dev);
+       int ret, value;
+
+       if (!nau8825) {
+               nau8825 = devm_kzalloc(dev, sizeof(*nau8825), GFP_KERNEL);
+               if (!nau8825)
+                       return -ENOMEM;
+               ret = nau8825_read_device_properties(dev, nau8825);
+               if (ret)
+                       return ret;
+       }
+
+       i2c_set_clientdata(i2c, nau8825);
+
+       nau8825->regmap = devm_regmap_init_i2c(i2c, &nau8825_regmap_config);
+       if (IS_ERR(nau8825->regmap))
+               return PTR_ERR(nau8825->regmap);
+       nau8825->dev = dev;
+       nau8825->irq = i2c->irq;
+
+       nau8825_print_device_properties(nau8825);
+
+       nau8825_reset_chip(nau8825->regmap);
+       ret = regmap_read(nau8825->regmap, NAU8825_REG_I2C_DEVICE_ID, &value);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device id from the NAU8825: %d\n",
+                       ret);
+               return ret;
+       }
+       if ((value & NAU8825_SOFTWARE_ID_MASK) !=
+                       NAU8825_SOFTWARE_ID_NAU8825) {
+               dev_err(dev, "Not a NAU8825 chip\n");
+               return -ENODEV;
+       }
+
+       nau8825_init_regs(nau8825);
+
+       if (i2c->irq)
+               nau8825_setup_irq(nau8825);
+
+       return snd_soc_register_codec(&i2c->dev, &nau8825_codec_driver,
+               &nau8825_dai, 1);
+}
+
+static int nau8825_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id nau8825_i2c_ids[] = {
+       { "nau8825", 0 },
+       { }
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8825_of_ids[] = {
+       { .compatible = "nuvoton,nau8825", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, nau8825_of_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8825_acpi_match[] = {
+       { "10508825", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, nau8825_acpi_match);
+#endif
+
+static struct i2c_driver nau8825_driver = {
+       .driver = {
+               .name = "nau8825",
+               .of_match_table = of_match_ptr(nau8825_of_ids),
+               .acpi_match_table = ACPI_PTR(nau8825_acpi_match),
+       },
+       .probe = nau8825_i2c_probe,
+       .remove = nau8825_i2c_remove,
+       .id_table = nau8825_i2c_ids,
+};
+module_i2c_driver(nau8825_driver);
+
+MODULE_DESCRIPTION("ASoC nau8825 driver");
+MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
new file mode 100644 (file)
index 0000000..dff8edb
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * NAU8825 ALSA SoC audio driver
+ *
+ * Copyright 2015 Google Inc.
+ * Author: Anatol Pomozov <anatol.pomozov@chrominium.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 __NAU8825_H__
+#define __NAU8825_H__
+
+#define NAU8825_REG_RESET              0x00
+#define NAU8825_REG_ENA_CTRL           0x01
+#define NAU8825_REG_CLK_DIVIDER                0x03
+#define NAU8825_REG_FLL1               0x04
+#define NAU8825_REG_FLL2               0x05
+#define NAU8825_REG_FLL3               0x06
+#define NAU8825_REG_FLL4               0x07
+#define NAU8825_REG_FLL5               0x08
+#define NAU8825_REG_FLL6               0x09
+#define NAU8825_REG_FLL_VCO_RSV                0x0a
+#define NAU8825_REG_HSD_CTRL           0x0c
+#define NAU8825_REG_JACK_DET_CTRL              0x0d
+#define NAU8825_REG_INTERRUPT_MASK             0x0f
+#define NAU8825_REG_IRQ_STATUS         0x10
+#define NAU8825_REG_INT_CLR_KEY_STATUS         0x11
+#define NAU8825_REG_INTERRUPT_DIS_CTRL         0x12
+#define NAU8825_REG_SAR_CTRL           0x13
+#define NAU8825_REG_KEYDET_CTRL                0x14
+#define NAU8825_REG_VDET_THRESHOLD_1           0x15
+#define NAU8825_REG_VDET_THRESHOLD_2           0x16
+#define NAU8825_REG_VDET_THRESHOLD_3           0x17
+#define NAU8825_REG_VDET_THRESHOLD_4           0x18
+#define NAU8825_REG_GPIO34_CTRL                0x19
+#define NAU8825_REG_GPIO12_CTRL                0x1a
+#define NAU8825_REG_TDM_CTRL           0x1b
+#define NAU8825_REG_I2S_PCM_CTRL1              0x1c
+#define NAU8825_REG_I2S_PCM_CTRL2              0x1d
+#define NAU8825_REG_LEFT_TIME_SLOT             0x1e
+#define NAU8825_REG_RIGHT_TIME_SLOT            0x1f
+#define NAU8825_REG_BIQ_CTRL           0x20
+#define NAU8825_REG_BIQ_COF1           0x21
+#define NAU8825_REG_BIQ_COF2           0x22
+#define NAU8825_REG_BIQ_COF3           0x23
+#define NAU8825_REG_BIQ_COF4           0x24
+#define NAU8825_REG_BIQ_COF5           0x25
+#define NAU8825_REG_BIQ_COF6           0x26
+#define NAU8825_REG_BIQ_COF7           0x27
+#define NAU8825_REG_BIQ_COF8           0x28
+#define NAU8825_REG_BIQ_COF9           0x29
+#define NAU8825_REG_BIQ_COF10          0x2a
+#define NAU8825_REG_ADC_RATE           0x2b
+#define NAU8825_REG_DAC_CTRL1          0x2c
+#define NAU8825_REG_DAC_CTRL2          0x2d
+#define NAU8825_REG_DAC_DGAIN_CTRL             0x2f
+#define NAU8825_REG_ADC_DGAIN_CTRL             0x30
+#define NAU8825_REG_MUTE_CTRL          0x31
+#define NAU8825_REG_HSVOL_CTRL         0x32
+#define NAU8825_REG_DACL_CTRL          0x33
+#define NAU8825_REG_DACR_CTRL          0x34
+#define NAU8825_REG_ADC_DRC_KNEE_IP12          0x38
+#define NAU8825_REG_ADC_DRC_KNEE_IP34          0x39
+#define NAU8825_REG_ADC_DRC_SLOPES             0x3a
+#define NAU8825_REG_ADC_DRC_ATKDCY             0x3b
+#define NAU8825_REG_DAC_DRC_KNEE_IP12          0x45
+#define NAU8825_REG_DAC_DRC_KNEE_IP34          0x46
+#define NAU8825_REG_DAC_DRC_SLOPES             0x47
+#define NAU8825_REG_DAC_DRC_ATKDCY             0x48
+#define NAU8825_REG_IMM_MODE_CTRL              0x4c
+#define NAU8825_REG_IMM_RMS_L          0x4d
+#define NAU8825_REG_IMM_RMS_R          0x4e
+#define NAU8825_REG_CLASSG_CTRL                0x50
+#define NAU8825_REG_OPT_EFUSE_CTRL             0x51
+#define NAU8825_REG_MISC_CTRL          0x55
+#define NAU8825_REG_I2C_DEVICE_ID              0x58
+#define NAU8825_REG_SARDOUT_RAM_STATUS         0x59
+#define NAU8825_REG_BIAS_ADJ           0x66
+#define NAU8825_REG_TRIM_SETTINGS              0x68
+#define NAU8825_REG_ANALOG_CONTROL_1           0x69
+#define NAU8825_REG_ANALOG_CONTROL_2           0x6a
+#define NAU8825_REG_ANALOG_ADC_1               0x71
+#define NAU8825_REG_ANALOG_ADC_2               0x72
+#define NAU8825_REG_RDAC               0x73
+#define NAU8825_REG_MIC_BIAS           0x74
+#define NAU8825_REG_BOOST              0x76
+#define NAU8825_REG_FEPGA              0x77
+#define NAU8825_REG_POWER_UP_CONTROL           0x7f
+#define NAU8825_REG_CHARGE_PUMP                0x80
+#define NAU8825_REG_CHARGE_PUMP_INPUT_READ             0x81
+#define NAU8825_REG_GENERAL_STATUS             0x82
+#define NAU8825_REG_MAX                NAU8825_REG_GENERAL_STATUS
+
+/* ENA_CTRL (0x1) */
+#define NAU8825_ENABLE_DACR_SFT        10
+#define NAU8825_ENABLE_DACR    (1 << NAU8825_ENABLE_DACR_SFT)
+#define NAU8825_ENABLE_DACL_SFT        9
+#define NAU8825_ENABLE_ADC_SFT 8
+#define NAU8825_ENABLE_SAR_SFT 1
+
+/* CLK_DIVIDER (0x3) */
+#define NAU8825_CLK_SRC_SFT                    15
+#define NAU8825_CLK_SRC_MASK                   (1 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_SRC_VCO                    (1 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_SRC_MCLK                   (0 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_MCLK_SRC_MASK              (0xf << 0)
+
+/* FLL1 (0x04) */
+#define NAU8825_FLL_RATIO_MASK                 (0x7f << 0)
+
+/* FLL3 (0x06) */
+#define NAU8825_FLL_INTEGER_MASK               (0x3ff << 0)
+
+/* FLL4 (0x07) */
+#define NAU8825_FLL_REF_DIV_MASK               (0x3 << 10)
+
+/* FLL5 (0x08) */
+#define NAU8825_FLL_FILTER_SW_MASK             (0x1 << 14)
+
+/* FLL6 (0x9) */
+#define NAU8825_DCO_EN_MASK                    (0x1 << 15)
+#define NAU8825_DCO_EN                         (0x1 << 15)
+#define NAU8825_DCO_DIS                                (0x0 << 15)
+#define NAU8825_SDM_EN_MASK                    (0x1 << 14)
+#define NAU8825_SDM_EN                         (0x1 << 14)
+#define NAU8825_SDM_DIS                                (0x0 << 14)
+
+/* HSD_CTRL (0xc) */
+#define NAU8825_HSD_AUTO_MODE  (1 << 6)
+/* 0 - short to GND, 1 - open */
+#define NAU8825_SPKR_DWN1R     (1 << 1)
+#define NAU8825_SPKR_DWN1L     (1 << 0)
+
+/* JACK_DET_CTRL (0xd) */
+#define NAU8825_JACK_DET_RESTART       (1 << 9)
+#define NAU8825_JACK_INSERT_DEBOUNCE_SFT       5
+#define NAU8825_JACK_INSERT_DEBOUNCE_MASK      (0x7 << NAU8825_JACK_INSERT_DEBOUNCE_SFT)
+#define NAU8825_JACK_EJECT_DEBOUNCE_SFT                2
+#define NAU8825_JACK_EJECT_DEBOUNCE_MASK       (0x7 << NAU8825_JACK_EJECT_DEBOUNCE_SFT)
+#define NAU8825_JACK_POLARITY  (1 << 1) /* 0 - active low, 1 - active high */
+
+/* INTERRUPT_MASK (0xf) */
+#define NAU8825_IRQ_OUTPUT_EN (1 << 11)
+#define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10)
+#define NAU8825_IRQ_KEY_RELEASE_EN (1 << 7)
+#define NAU8825_IRQ_KEY_SHORT_PRESS_EN (1 << 5)
+#define NAU8825_IRQ_EJECT_EN (1 << 2)
+
+/* IRQ_STATUS (0x10) */
+#define NAU8825_HEADSET_COMPLETION_IRQ (1 << 10)
+#define NAU8825_SHORT_CIRCUIT_IRQ      (1 << 9)
+#define NAU8825_IMPEDANCE_MEAS_IRQ     (1 << 8)
+#define NAU8825_KEY_IRQ_MASK   (0x7 << 5)
+#define NAU8825_KEY_RELEASE_IRQ        (1 << 7)
+#define NAU8825_KEY_LONG_PRESS_IRQ     (1 << 6)
+#define NAU8825_KEY_SHORT_PRESS_IRQ    (1 << 5)
+#define NAU8825_MIC_DETECTION_IRQ      (1 << 4)
+#define NAU8825_JACK_EJECTION_IRQ_MASK (3 << 2)
+#define NAU8825_JACK_EJECTION_DETECTED (1 << 2)
+#define NAU8825_JACK_INSERTION_IRQ_MASK        (3 << 0)
+#define NAU8825_JACK_INSERTION_DETECTED        (1 << 0)
+
+/* INTERRUPT_DIS_CTRL (0x12) */
+#define NAU8825_IRQ_HEADSET_COMPLETE_DIS (1 << 10)
+#define NAU8825_IRQ_KEY_RELEASE_DIS (1 << 7)
+#define NAU8825_IRQ_KEY_SHORT_PRESS_DIS (1 << 5)
+#define NAU8825_IRQ_EJECT_DIS (1 << 2)
+
+/* SAR_CTRL (0x13) */
+#define NAU8825_SAR_ADC_EN_SFT 12
+#define NAU8825_SAR_ADC_EN     (1 << NAU8825_SAR_ADC_EN_SFT)
+#define NAU8825_SAR_INPUT_MASK (1 << 11)
+#define NAU8825_SAR_INPUT_JKSLV        (1 << 11)
+#define NAU8825_SAR_INPUT_JKR2 (0 << 11)
+#define NAU8825_SAR_TRACKING_GAIN_SFT  8
+#define NAU8825_SAR_TRACKING_GAIN_MASK (0x7 << NAU8825_SAR_TRACKING_GAIN_SFT)
+#define NAU8825_SAR_COMPARE_TIME_SFT   2
+#define NAU8825_SAR_COMPARE_TIME_MASK  (3 << 2)
+#define NAU8825_SAR_SAMPLING_TIME_SFT  0
+#define NAU8825_SAR_SAMPLING_TIME_MASK (3 << 0)
+
+/* KEYDET_CTRL (0x14) */
+#define NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT   12
+#define NAU8825_KEYDET_SHORTKEY_DEBOUNCE_MASK  (0x3 << NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT)
+#define NAU8825_KEYDET_LEVELS_NR_SFT   8
+#define NAU8825_KEYDET_LEVELS_NR_MASK  (0x7 << 8)
+#define NAU8825_KEYDET_HYSTERESIS_SFT  0
+#define NAU8825_KEYDET_HYSTERESIS_MASK 0xf
+
+/* GPIO12_CTRL (0x1a) */
+#define NAU8825_JKDET_PULL_UP  (1 << 11) /* 0 - pull down, 1 - pull up */
+#define NAU8825_JKDET_PULL_EN  (1 << 9) /* 0 - enable pull, 1 - disable */
+#define NAU8825_JKDET_OUTPUT_EN        (1 << 8) /* 0 - enable input, 1 - enable output */
+
+/* I2S_PCM_CTRL1 (0x1c) */
+#define NAU8825_I2S_BP_SFT     7
+#define NAU8825_I2S_BP_MASK    (1 << NAU8825_I2S_BP_SFT)
+#define NAU8825_I2S_BP_INV     (1 << NAU8825_I2S_BP_SFT)
+#define NAU8825_I2S_PCMB_SFT   6
+#define NAU8825_I2S_PCMB_MASK  (1 << NAU8825_I2S_PCMB_SFT)
+#define NAU8825_I2S_PCMB_EN    (1 << NAU8825_I2S_PCMB_SFT)
+#define NAU8825_I2S_DL_SFT     2
+#define NAU8825_I2S_DL_MASK    (0x3 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_16      (0 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_20      (1 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_24      (2 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_32      (3 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DF_SFT     0
+#define NAU8825_I2S_DF_MASK    (0x3 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_RIGTH   (0 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_LEFT    (1 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_I2S     (2 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_PCM_AB  (3 << NAU8825_I2S_DF_SFT)
+
+/* I2S_PCM_CTRL2 (0x1d) */
+#define NAU8825_I2S_TRISTATE   (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
+#define NAU8825_I2S_MS_SFT     3
+#define NAU8825_I2S_MS_MASK    (1 << NAU8825_I2S_MS_SFT)
+#define NAU8825_I2S_MS_MASTER  (1 << NAU8825_I2S_MS_SFT)
+#define NAU8825_I2S_MS_SLAVE   (0 << NAU8825_I2S_MS_SFT)
+
+/* ADC_RATE (0x2b) */
+#define NAU8825_ADC_SYNC_DOWN_SFT      0
+#define NAU8825_ADC_SYNC_DOWN_MASK     0x3
+#define NAU8825_ADC_SYNC_DOWN_32       0
+#define NAU8825_ADC_SYNC_DOWN_64       1
+#define NAU8825_ADC_SYNC_DOWN_128      2
+#define NAU8825_ADC_SYNC_DOWN_256      3
+
+/* DAC_CTRL1 (0x2c) */
+#define NAU8825_DAC_CLIP_OFF   (1 << 7)
+#define NAU8825_DAC_OVERSAMPLE_SFT     0
+#define NAU8825_DAC_OVERSAMPLE_MASK    0x7
+#define NAU8825_DAC_OVERSAMPLE_64      0
+#define NAU8825_DAC_OVERSAMPLE_256     1
+#define NAU8825_DAC_OVERSAMPLE_128     2
+#define NAU8825_DAC_OVERSAMPLE_32      4
+
+/* MUTE_CTRL (0x31) */
+#define NAU8825_DAC_ZERO_CROSSING_EN   (1 << 9)
+#define NAU8825_DAC_SOFT_MUTE  (1 << 9)
+
+/* HSVOL_CTRL (0x32) */
+#define NAU8825_HP_MUTE        (1 << 15)
+
+/* DACL_CTRL (0x33) */
+#define NAU8825_DACL_CH_SEL_SFT        9
+
+/* DACR_CTRL (0x34) */
+#define NAU8825_DACR_CH_SEL_SFT        9
+
+/* I2C_DEVICE_ID (0x58) */
+#define NAU8825_GPIO2JD1       (1 << 7)
+#define NAU8825_SOFTWARE_ID_MASK       0x3
+#define NAU8825_SOFTWARE_ID_NAU8825    0x0
+
+/* BIAS_ADJ (0x66) */
+#define NAU8825_BIAS_VMID      (1 << 6)
+#define NAU8825_BIAS_VMID_SEL_SFT      4
+#define NAU8825_BIAS_VMID_SEL_MASK     (3 << NAU8825_BIAS_VMID_SEL_SFT)
+
+/* ANALOG_CONTROL_2 (0x6a) */
+#define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12)
+#define NAU8825_DAC_CAPACITOR_MSB (1 << 1)
+#define NAU8825_DAC_CAPACITOR_LSB (1 << 0)
+
+/* ANALOG_ADC_2 (0x72) */
+#define NAU8825_ADC_VREFSEL_MASK       (0x3 << 8)
+#define NAU8825_ADC_VREFSEL_ANALOG     (0 << 8)
+#define NAU8825_ADC_VREFSEL_VMID       (1 << 8)
+#define NAU8825_ADC_VREFSEL_VMID_PLUS_0_5DB    (2 << 8)
+#define NAU8825_ADC_VREFSEL_VMID_PLUS_1DB      (3 << 8)
+#define NAU8825_POWERUP_ADCL   (1 << 6)
+
+/* MIC_BIAS (0x74) */
+#define NAU8825_MICBIAS_JKSLV  (1 << 14)
+#define NAU8825_MICBIAS_JKR2   (1 << 12)
+#define NAU8825_MICBIAS_POWERUP_SFT    8
+#define NAU8825_MICBIAS_VOLTAGE_SFT    0
+#define NAU8825_MICBIAS_VOLTAGE_MASK   0x7
+
+/* BOOST (0x76) */
+#define NAU8825_PRECHARGE_DIS  (1 << 13)
+#define NAU8825_GLOBAL_BIAS_EN (1 << 12)
+#define NAU8825_HP_BOOST_G_DIS (1 << 8)
+#define NAU8825_SHORT_SHUTDOWN_EN      (1 << 6)
+
+/* POWER_UP_CONTROL (0x7f) */
+#define NAU8825_POWERUP_INTEGR_R       (1 << 5)
+#define NAU8825_POWERUP_INTEGR_L       (1 << 4)
+#define NAU8825_POWERUP_DRV_IN_R       (1 << 3)
+#define NAU8825_POWERUP_DRV_IN_L       (1 << 2)
+#define NAU8825_POWERUP_HP_DRV_R       (1 << 1)
+#define NAU8825_POWERUP_HP_DRV_L       (1 << 0)
+
+/* CHARGE_PUMP (0x80) */
+#define NAU8825_JAMNODCLOW     (1 << 10)
+#define NAU8825_POWER_DOWN_DACR        (1 << 9)
+#define NAU8825_POWER_DOWN_DACL        (1 << 8)
+#define NAU8825_CHANRGE_PUMP_EN        (1 << 5)
+
+
+/* System Clock Source */
+enum {
+       NAU8825_CLK_MCLK = 0,
+       NAU8825_CLK_INTERNAL,
+};
+
+struct nau8825 {
+       struct device *dev;
+       struct regmap *regmap;
+       struct snd_soc_dapm_context *dapm;
+       struct snd_soc_jack *jack;
+       struct clk *mclk;
+       int irq;
+       int mclk_freq; /* 0 - mclk is disabled */
+       int button_pressed;
+       int micbias_voltage;
+       int vref_impedance;
+       bool jkdet_enable;
+       bool jkdet_pull_enable;
+       bool jkdet_pull_up;
+       int jkdet_polarity;
+       int sar_threshold_num;
+       int sar_threshold[8];
+       int sar_hysteresis;
+       int sar_voltage;
+       int sar_compare_time;
+       int sar_sampling_time;
+       int key_debounce;
+       int jack_insert_debounce;
+       int jack_eject_debounce;
+};
+
+int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack);
+
+
+#endif  /* __NAU8825_H__ */
index 91d5166bd3a1f883e8d3a7f5bd60511b7f50a781..a4b910efbd455eba52f086053ea9a6ec4789ef03 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/dmi.h>
-#include <linux/acpi.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <sound/jack.h>
-#include <linux/workqueue.h>
-#include <sound/hda_verbs.h>
+#include <linux/regmap.h>
 
 #include "rl6347a.h"
 
index 1cb56e50b7f339f70eb23874943be5c05fc10ad0..e127919cb36b3334aac843abb7cd4391b092ed74 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __RL6347A_H__
 #define __RL6347A_H__
 
+#include <sound/hda_verbs.h>
+
 #define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
 
 #define RL6347A_VENDOR_REGISTERS       0x20
index bd9365885f73f508fa88de0908215473efaaddb3..af2ed774b5529919486587e732ba6924dd39bb4a 100644 (file)
@@ -29,7 +29,6 @@
 #include <sound/jack.h>
 #include <linux/workqueue.h>
 #include <sound/rt286.h>
-#include <sound/hda_verbs.h>
 
 #include "rl6347a.h"
 #include "rt286.h"
@@ -38,7 +37,7 @@
 #define RT288_VENDOR_ID 0x10ec0288
 
 struct rt286_priv {
-       const struct reg_default *index_cache;
+       struct reg_default *index_cache;
        int index_cache_size;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
@@ -1161,7 +1160,11 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
                return -ENODEV;
        }
 
-       rt286->index_cache = rt286_index_def;
+       rt286->index_cache = devm_kmemdup(&i2c->dev, rt286_index_def,
+                                         sizeof(rt286_index_def), GFP_KERNEL);
+       if (!rt286->index_cache)
+               return -ENOMEM;
+
        rt286->index_cache_size = INDEX_CACHE_SIZE;
        rt286->i2c = i2c;
        i2c_set_clientdata(i2c, rt286);
index f823eb502367dccad4b93e71ac7e06d30c0bccdf..b3f795c60749b8f8473184f0872329d4578b8e48 100644 (file)
@@ -28,7 +28,6 @@
 #include <sound/jack.h>
 #include <linux/workqueue.h>
 #include <sound/rt298.h>
-#include <sound/hda_verbs.h>
 
 #include "rl6347a.h"
 #include "rt298.h"
@@ -49,7 +48,7 @@ struct rt298_priv {
        int is_hp_in;
 };
 
-static struct reg_default rt298_index_def[] = {
+static const struct reg_default rt298_index_def[] = {
        { 0x01, 0xa5a8 },
        { 0x02, 0x8e95 },
        { 0x03, 0x0002 },
@@ -129,7 +128,7 @@ static bool rt298_volatile_register(struct device *dev, unsigned int reg)
        case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0):
                return true;
        default:
-               return true;
+               return false;
        }
 
 
@@ -1165,7 +1164,11 @@ static int rt298_i2c_probe(struct i2c_client *i2c,
                return -ENODEV;
        }
 
-       rt298->index_cache = rt298_index_def;
+       rt298->index_cache = devm_kmemdup(&i2c->dev, rt298_index_def,
+                                         sizeof(rt298_index_def), GFP_KERNEL);
+       if (!rt298->index_cache)
+               return -ENOMEM;
+
        rt298->index_cache_size = INDEX_CACHE_SIZE;
        rt298->i2c = i2c;
        i2c_set_clientdata(i2c, rt298);
index e1ceeb885f7d64858248b07206db23796a08f084..f2beb1aa5763dfe99dc6de821f4c9367446773a7 100644 (file)
@@ -405,11 +405,14 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
        SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
                        RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
                        175, 0, dac_vol_tlv),
-       /* IN1/IN2 Control */
+       /* IN1/IN2/IN3 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
                RT5640_BST_SFT1, 8, 0, bst_tlv),
        SOC_SINGLE_TLV("IN2 Boost", RT5640_IN3_IN4,
                RT5640_BST_SFT2, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN3 Boost", RT5640_IN1_IN2,
+               RT5640_BST_SFT2, 8, 0, bst_tlv),
+
        /* INL/INR Volume Control */
        SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL,
                        RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT,
@@ -598,6 +601,8 @@ static const struct snd_kcontrol_new rt5640_rec_l_mix[] = {
                        RT5640_M_HP_L_RM_L_SFT, 1, 1),
        SOC_DAPM_SINGLE("INL Switch", RT5640_REC_L2_MIXER,
                        RT5640_M_IN_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_BST2_RM_L_SFT, 1, 1),
        SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_L2_MIXER,
                        RT5640_M_BST4_RM_L_SFT, 1, 1),
        SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_L2_MIXER,
@@ -611,6 +616,8 @@ static const struct snd_kcontrol_new rt5640_rec_r_mix[] = {
                        RT5640_M_HP_R_RM_R_SFT, 1, 1),
        SOC_DAPM_SINGLE("INR Switch", RT5640_REC_R2_MIXER,
                        RT5640_M_IN_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_BST2_RM_R_SFT, 1, 1),
        SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_R2_MIXER,
                        RT5640_M_BST4_RM_R_SFT, 1, 1),
        SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_R2_MIXER,
@@ -1065,6 +1072,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("IN1N"),
        SND_SOC_DAPM_INPUT("IN2P"),
        SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_INPUT("IN3P"),
+       SND_SOC_DAPM_INPUT("IN3N"),
        SND_SOC_DAPM_PGA("DMIC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("DMIC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("DMIC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1081,6 +1090,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
                RT5640_PWR_BST1_BIT, 0, NULL, 0),
        SND_SOC_DAPM_PGA("BST2", RT5640_PWR_ANLG2,
                RT5640_PWR_BST4_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST3", RT5640_PWR_ANLG2,
+               RT5640_PWR_BST2_BIT, 0, NULL, 0),
        /* Input Volume */
        SND_SOC_DAPM_PGA("INL VOL", RT5640_PWR_VOL,
                RT5640_PWR_IN_L_BIT, 0, NULL, 0),
@@ -1310,6 +1321,7 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
 static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"IN1P", NULL, "LDO2"},
        {"IN2P", NULL, "LDO2"},
+       {"IN3P", NULL, "LDO2"},
 
        {"DMIC L1", NULL, "DMIC1"},
        {"DMIC R1", NULL, "DMIC1"},
@@ -1320,18 +1332,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
        {"BST1", NULL, "IN1N"},
        {"BST2", NULL, "IN2P"},
        {"BST2", NULL, "IN2N"},
+       {"BST3", NULL, "IN3P"},
+       {"BST3", NULL, "IN3N"},
 
        {"INL VOL", NULL, "IN2P"},
        {"INR VOL", NULL, "IN2N"},
 
        {"RECMIXL", "HPOL Switch", "HPOL"},
        {"RECMIXL", "INL Switch", "INL VOL"},
+       {"RECMIXL", "BST3 Switch", "BST3"},
        {"RECMIXL", "BST2 Switch", "BST2"},
        {"RECMIXL", "BST1 Switch", "BST1"},
        {"RECMIXL", "OUT MIXL Switch", "OUT MIXL"},
 
        {"RECMIXR", "HPOR Switch", "HPOR"},
        {"RECMIXR", "INR Switch", "INR VOL"},
+       {"RECMIXR", "BST3 Switch", "BST3"},
        {"RECMIXR", "BST2 Switch", "BST2"},
        {"RECMIXR", "BST1 Switch", "BST1"},
        {"RECMIXR", "OUT MIXR Switch", "OUT MIXR"},
@@ -2260,6 +2276,10 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
                                        RT5640_IN_DF2, RT5640_IN_DF2);
 
+       if (rt5640->pdata.in3_diff)
+               regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
+                                       RT5640_IN_DF2, RT5640_IN_DF2);
+
        rt5640->hp_mute = 1;
 
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
index 5c101af0ac630dddf1cf12085846d5cfd9c08911..28132375e4274a6e94e830c2fe1e8fcddd255747 100644 (file)
@@ -42,6 +42,8 @@
 
 #define RT5645_PR_BASE (RT5645_PR_RANGE_BASE + (0 * RT5645_PR_SPACING))
 
+#define RT5645_HWEQ_NUM 57
+
 static const struct regmap_range_cfg rt5645_ranges[] = {
        {
                .name = "PR",
@@ -224,6 +226,11 @@ static const struct reg_default rt5645_reg[] = {
        { 0xff, 0x6308 },
 };
 
+struct rt5645_eq_param_s {
+       unsigned short reg;
+       unsigned short val;
+};
+
 static const char *const rt5645_supply_names[] = {
        "avdd",
        "cpvdd",
@@ -240,6 +247,7 @@ struct rt5645_priv {
        struct snd_soc_jack *btn_jack;
        struct delayed_work jack_detect_work;
        struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
+       struct rt5645_eq_param_s *eq_param;
 
        int codec_type;
        int sysclk;
@@ -469,6 +477,94 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv,
        8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
 );
 
+/* {-6, -4.5, -3, -1.5, 0, 0.82, 1.58, 2.28} dB */
+static const DECLARE_TLV_DB_RANGE(spk_clsd_tlv,
+       0, 4, TLV_DB_SCALE_ITEM(-600, 150, 0),
+       5, 5, TLV_DB_SCALE_ITEM(82, 0, 0),
+       6, 6, TLV_DB_SCALE_ITEM(158, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(228, 0, 0)
+);
+
+static int rt5645_hweq_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s);
+
+       return 0;
+}
+
+static int rt5645_hweq_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+       struct rt5645_eq_param_s *eq_param =
+               (struct rt5645_eq_param_s *)ucontrol->value.bytes.data;
+       int i;
+
+       for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+               eq_param[i].reg = cpu_to_be16(rt5645->eq_param[i].reg);
+               eq_param[i].val = cpu_to_be16(rt5645->eq_param[i].val);
+       }
+
+       return 0;
+}
+
+static bool rt5645_validate_hweq(unsigned short reg)
+{
+       if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) |
+               (reg == RT5645_EQ_CTRL2))
+               return true;
+
+       return false;
+}
+
+static int rt5645_hweq_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+       struct rt5645_eq_param_s *eq_param =
+               (struct rt5645_eq_param_s *)ucontrol->value.bytes.data;
+       int i;
+
+       for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+               eq_param[i].reg = be16_to_cpu(eq_param[i].reg);
+               eq_param[i].val = be16_to_cpu(eq_param[i].val);
+       }
+
+       /* The final setting of the table should be RT5645_EQ_CTRL2 */
+       for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) {
+               if (eq_param[i].reg == 0)
+                       continue;
+               else if (eq_param[i].reg != RT5645_EQ_CTRL2)
+                       return 0;
+               else
+                       break;
+       }
+
+       for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+               if (!rt5645_validate_hweq(eq_param[i].reg) &&
+                       eq_param[i].reg != 0)
+                       return 0;
+               else if (eq_param[i].reg == 0)
+                       break;
+       }
+
+       memcpy(rt5645->eq_param, eq_param,
+               RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s));
+
+       return 0;
+}
+
+#define RT5645_HWEQ(xname) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = rt5645_hweq_info, \
+       .get = rt5645_hweq_get, \
+       .put = rt5645_hweq_put \
+}
+
 static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        /* Speaker Output Volume */
        SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
@@ -476,6 +572,10 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
                RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
 
+       /* ClassD modulator Speaker Gain Ratio */
+       SOC_SINGLE_TLV("Speaker ClassD Playback Volume", RT5645_SPO_CLSD_RATIO,
+               RT5645_SPK_G_CLSD_SFT, 7, 0, spk_clsd_tlv),
+
        /* Headphone Output Volume */
        SOC_DOUBLE("Headphone Channel Switch", RT5645_HP_VOL,
                RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
@@ -529,6 +629,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
        /* I2S2 function select */
        SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
                1, 1),
+       RT5645_HWEQ("Speaker HWEQ"),
 };
 
 /**
@@ -619,6 +720,22 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 
 }
 
+static int rt5645_enable_hweq(struct snd_soc_codec *codec)
+{
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+               if (rt5645_validate_hweq(rt5645->eq_param[i].reg))
+                       regmap_write(rt5645->regmap, rt5645->eq_param[i].reg,
+                                       rt5645->eq_param[i].val);
+               else
+                       break;
+       }
+
+       return 0;
+}
+
 /**
  * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
  * @codec: SoC audio codec device.
@@ -1523,6 +1640,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
+               rt5645_enable_hweq(codec);
                snd_soc_update_bits(codec, RT5645_PWR_DIG1,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
                        RT5645_PWR_CLS_D_L,
@@ -1531,6 +1649,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_write(codec, RT5645_EQ_CTRL2, 0);
                snd_soc_update_bits(codec, RT5645_PWR_DIG1,
                        RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
                        RT5645_PWR_CLS_D_L, 0);
@@ -2733,6 +2852,10 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
                        RT5645_PWR_FV1 | RT5645_PWR_FV2,
                        RT5645_PWR_FV1 | RT5645_PWR_FV2);
+               if (rt5645->en_button_func &&
+                       snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+                       queue_delayed_work(system_power_efficient_wq,
+                               &rt5645->jack_detect_work, msecs_to_jiffies(0));
                break;
 
        case SND_SOC_BIAS_OFF:
@@ -2829,6 +2952,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
                        snd_soc_dapm_sync(dapm);
                        rt5645->jack_type = SND_JACK_HEADPHONE;
                }
+               if (rt5645->pdata.jd_invert)
+                       regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
        } else { /* jack out */
                rt5645->jack_type = 0;
 
@@ -2847,6 +2973,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
                        snd_soc_dapm_disable_pin(dapm, "LDO2");
                snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
                snd_soc_dapm_sync(dapm);
+               if (rt5645->pdata.jd_invert)
+                       regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+                               RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
        }
 
        return rt5645->jack_type;
@@ -3038,6 +3167,9 @@ static int rt5645_probe(struct snd_soc_codec *codec)
                snd_soc_dapm_sync(dapm);
        }
 
+       rt5645->eq_param = devm_kzalloc(codec->dev,
+               RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s), GFP_KERNEL);
+
        return 0;
 }
 
@@ -3098,7 +3230,7 @@ static struct snd_soc_dai_driver rt5645_dai[] = {
                .capture = {
                        .stream_name = "AIF1 Capture",
                        .channels_min = 1,
-                       .channels_max = 2,
+                       .channels_max = 4,
                        .rates = RT5645_STEREO_RATES,
                        .formats = RT5645_FORMATS,
                },
@@ -3209,9 +3341,42 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"),
                },
        },
+       {
+               .ident = "Google Reks",
+               .callback = strago_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Reks"),
+               },
+       },
        { }
 };
 
+static struct rt5645_platform_data buddy_platform_data = {
+       .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
+       .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+       .jd_mode = 3,
+       .jd_invert = true,
+};
+
+static int buddy_quirk_cb(const struct dmi_system_id *id)
+{
+       rt5645_pdata = &buddy_platform_data;
+
+       return 1;
+}
+
+static struct dmi_system_id dmi_platform_intel_broadwell[] = {
+       {
+               .ident = "Chrome Buddy",
+               .callback = buddy_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
+               },
+       },
+       { }
+};
+
+
 static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
 {
        rt5645->pdata.in2_diff = device_property_read_bool(dev,
@@ -3244,7 +3409,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
        if (pdata)
                rt5645->pdata = *pdata;
-       else if (dmi_check_system(dmi_platform_intel_braswell))
+       else if (dmi_check_system(dmi_platform_intel_braswell) ||
+                       dmi_check_system(dmi_platform_intel_broadwell))
                rt5645->pdata = *rt5645_pdata;
        else
                rt5645_parse_dt(rt5645, &i2c->dev);
@@ -3472,6 +3638,8 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
                RT5645_CBJ_MN_JD);
        regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, RT5645_CBJ_BST1_EN,
                0);
+       msleep(20);
+       regmap_write(rt5645->regmap, RT5645_RESET, 0);
 }
 
 static struct i2c_driver rt5645_i2c_driver = {
index 8c964cfb120ddc4130e5d39e9ab96ae34623eb34..093e46d559fbab24aa05efc5c74a2e8488fa49d0 100644 (file)
 #define RT5645_G_OM_L_SM_L_SFT                 6
 #define RT5645_M_BST1_L_SM_L                   (0x1 << 5)
 #define RT5645_M_BST1_L_SM_L_SFT               5
+#define RT5645_M_BST3_L_SM_L                   (0x1 << 4)
+#define RT5645_M_BST3_L_SM_L_SFT               4
 #define RT5645_M_IN_L_SM_L                     (0x1 << 3)
 #define RT5645_M_IN_L_SM_L_SFT                 3
-#define RT5645_M_DAC_L1_SM_L                   (0x1 << 1)
-#define RT5645_M_DAC_L1_SM_L_SFT               1
 #define RT5645_M_DAC_L2_SM_L                   (0x1 << 2)
 #define RT5645_M_DAC_L2_SM_L_SFT               2
-#define RT5645_M_BST3_L_SM_L                   (0x1 << 4)
-#define RT5645_M_BST3_L_SM_L_SFT               4
+#define RT5645_M_DAC_L1_SM_L                   (0x1 << 1)
+#define RT5645_M_DAC_L1_SM_L_SFT               1
 
 /* SPK Right Mixer Control (0x47) */
 #define RT5645_G_RM_R_SM_R_MASK                        (0x3 << 14)
 #define RT5645_G_OM_R_SM_R_SFT                 6
 #define RT5645_M_BST2_R_SM_R                   (0x1 << 5)
 #define RT5645_M_BST2_R_SM_R_SFT               5
+#define RT5645_M_BST3_R_SM_R                   (0x1 << 4)
+#define RT5645_M_BST3_R_SM_R_SFT               4
 #define RT5645_M_IN_R_SM_R                     (0x1 << 3)
 #define RT5645_M_IN_R_SM_R_SFT                 3
-#define RT5645_M_DAC_R1_SM_R                   (0x1 << 1)
-#define RT5645_M_DAC_R1_SM_R_SFT               1
 #define RT5645_M_DAC_R2_SM_R                   (0x1 << 2)
 #define RT5645_M_DAC_R2_SM_R_SFT               2
-#define RT5645_M_BST3_R_SM_R                   (0x1 << 4)
-#define RT5645_M_BST3_R_SM_R_SFT               4
+#define RT5645_M_DAC_R1_SM_R                   (0x1 << 1)
+#define RT5645_M_DAC_R1_SM_R_SFT               1
 
 /* SPOLMIX Control (0x48) */
 #define RT5645_M_DAC_L1_SPM_L                  (0x1 << 15)
 #define RT5645_M_SV_R_SPM_R                    (0x1 << 0)
 #define RT5645_M_SV_R_SPM_R_SFT                        0
 
+/* SPOMIX Ratio Control (0x4a) */
+#define RT5645_SPK_G_CLSD_MASK                 (0x7 << 0)
+#define RT5645_SPK_G_CLSD_SFT                  0
+
 /* Mono Output Mixer Control (0x4c) */
+#define RT5645_G_MONOMIX_MASK                  (0x1 << 10)
+#define RT5645_G_MONOMIX_SFT                   10
 #define RT5645_M_OV_L_MM                       (0x1 << 9)
 #define RT5645_M_OV_L_MM_SFT                   9
 #define RT5645_M_DAC_L2_MA                     (0x1 << 8)
 #define RT5645_M_DAC_L2_MA_SFT                 8
-#define RT5645_G_MONOMIX_MASK                  (0x1 << 10)
-#define RT5645_G_MONOMIX_SFT                   10
 #define RT5645_M_BST2_MM                       (0x1 << 4)
 #define RT5645_M_BST2_MM_SFT                   4
 #define RT5645_M_DAC_R1_MM                     (0x1 << 3)
 #define RT5645_PWR_CLS_D_R_BIT                 9
 #define RT5645_PWR_CLS_D_L                     (0x1 << 8)
 #define RT5645_PWR_CLS_D_L_BIT                 8
-#define RT5645_PWR_ADC_R                       (0x1 << 1)
-#define RT5645_PWR_ADC_R_BIT                   1
 #define RT5645_PWR_DAC_L2                      (0x1 << 7)
 #define RT5645_PWR_DAC_L2_BIT                  7
 #define RT5645_PWR_DAC_R2                      (0x1 << 6)
 #define RT5645_OT_P_NOR                                (0x0 << 10)
 #define RT5645_OT_P_INV                                (0x1 << 10)
 #define RT5645_IRQ_JD_1_1_EN                   (0x1 << 9)
+#define RT5645_JD_1_1_MASK                     (0x1 << 7)
+#define RT5645_JD_1_1_SFT                      7
+#define RT5645_JD_1_1_NOR                      (0x0 << 7)
+#define RT5645_JD_1_1_INV                      (0x1 << 7)
 
 /* IRQ Control 2 (0xbe) */
 #define RT5645_IRQ_MB1_OC_MASK                 (0x1 << 15)
index ddb0203fc6495b520f4695be9e94e62a7ea56026..86b81a60ac52bb4750da5981d62a210815d515c4 100644 (file)
@@ -723,17 +723,11 @@ static struct snd_soc_codec_driver ssm2518_codec_driver = {
        .num_dapm_routes = ARRAY_SIZE(ssm2518_routes),
 };
 
-static bool ssm2518_register_volatile(struct device *dev, unsigned int reg)
-{
-       return false;
-}
-
 static const struct regmap_config ssm2518_regmap_config = {
        .val_bits = 8,
        .reg_bits = 8,
 
        .max_register = SSM2518_REG_DRC_9,
-       .volatile_reg = ssm2518_register_volatile,
 
        .cache_type = REGCACHE_RBTREE,
        .reg_defaults = ssm2518_reg_defaults,
index 8739126a1f6f60d4c9e3eac08aaf337c2f7b3a2b..a564759845f980119a29c49633cb537ef685bcd9 100644 (file)
@@ -80,6 +80,7 @@ struct aic3x_priv {
        unsigned int sysclk;
        unsigned int dai_fmt;
        unsigned int tdm_delay;
+       unsigned int slot_width;
        struct list_head list;
        int master;
        int gpio_reset;
@@ -1025,10 +1026,14 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
        u16 d, pll_d = 1;
        int clk;
+       int width = aic3x->slot_width;
+
+       if (!width)
+               width = params_width(params);
 
        /* select data word length */
        data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
-       switch (params_width(params)) {
+       switch (width) {
        case 16:
                break;
        case 20:
@@ -1170,12 +1175,16 @@ static int aic3x_prepare(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int delay = 0;
+       int width = aic3x->slot_width;
+
+       if (!width)
+               width = substream->runtime->sample_bits;
 
        /* TDM slot selection only valid in DSP_A/_B mode */
        if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A)
-               delay += (aic3x->tdm_delay + 1);
+               delay += (aic3x->tdm_delay*width + 1);
        else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B)
-               delay += aic3x->tdm_delay;
+               delay += aic3x->tdm_delay*width;
 
        /* Configure data delay */
        snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
@@ -1296,7 +1305,20 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       aic3x->tdm_delay = lsb * slot_width;
+       switch (slot_width) {
+       case 16:
+       case 20:
+       case 24:
+       case 32:
+               break;
+       default:
+               dev_err(codec->dev, "Unsupported slot width %d\n", slot_width);
+               return -EINVAL;
+       }
+
+
+       aic3x->tdm_delay = lsb;
+       aic3x->slot_width = slot_width;
 
        /* DOUT in high-impedance on inactive bit clocks */
        snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA,
index 2713e1845cbcd93f71232fbc2141784a7c540223..a5a4e9f75c57f89e88f3047d980cf286f36569af 100644 (file)
@@ -1612,19 +1612,16 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
                return;
 
        /* Set the constraints according to the already configured stream */
-       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+       snd_pcm_hw_constraint_single(slv_substream->runtime,
                                SNDRV_PCM_HW_PARAM_RATE,
-                               twl4030->rate,
                                twl4030->rate);
 
-       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+       snd_pcm_hw_constraint_single(slv_substream->runtime,
                                SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                               twl4030->sample_bits,
                                twl4030->sample_bits);
 
-       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+       snd_pcm_hw_constraint_single(slv_substream->runtime,
                                SNDRV_PCM_HW_PARAM_CHANNELS,
-                               twl4030->channels,
                                twl4030->channels);
 }
 
@@ -1669,9 +1666,9 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
                        /* In option2 4 channel is not supported, set the
                         * constraint for the first stream for channels, the
                         * second stream will 'inherit' this cosntraint */
-                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                       snd_pcm_hw_constraint_single(substream->runtime,
                                                     SNDRV_PCM_HW_PARAM_CHANNELS,
-                                                    2, 2);
+                                                    2);
                }
                twl4030->master_substream = substream;
        }
index e1902638053490dda1ab695cf989c91239769ea7..e4c694c758b810e4ae041436fdb364baf4684fd6 100644 (file)
@@ -150,14 +150,12 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
                         master_runtime->sample_bits,
                         master_runtime->rate);
 
-               snd_pcm_hw_constraint_minmax(substream->runtime,
+               snd_pcm_hw_constraint_single(substream->runtime,
                                             SNDRV_PCM_HW_PARAM_RATE,
-                                            master_runtime->rate,
                                             master_runtime->rate);
 
-               snd_pcm_hw_constraint_minmax(substream->runtime,
+               snd_pcm_hw_constraint_single(substream->runtime,
                                             SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            master_runtime->sample_bits,
                                             master_runtime->sample_bits);
 
                uda134x->slave_substream = substream;
index 80fb1dc81f6cfb89544da1ee393ce1fb3794f253..7693c1129babf0e42c58b5ca93832052374cb426 100644 (file)
@@ -307,11 +307,10 @@ static int wl1273_startup(struct snd_pcm_substream *substream,
 
        switch (wl1273->mode) {
        case WL1273_MODE_BT:
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_RATE,
-                                            8000, 8000);
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
+               snd_pcm_hw_constraint_single(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_RATE, 8000);
+               snd_pcm_hw_constraint_single(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_CHANNELS, 1);
                break;
        case WL1273_MODE_FM_RX:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
index 786abd02b1406af3a6b653d22b70742686f2650d..a67ea10f41a1adce51e3625986e1170904429837 100644 (file)
@@ -620,7 +620,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int anc_active = ucontrol->value.integer.value[0];
+       unsigned int anc_active = ucontrol->value.integer.value[0];
        int ret;
 
        if (anc_active > 1)
@@ -653,7 +653,7 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
-       int val = ucontrol->value.integer.value[0];
+       unsigned int val = ucontrol->value.integer.value[0];
        int ret;
 
        if (val > 1)
index 9756578fc7526a3182039bad491d3388e297de57..c04c0bc6f58ad434de2bbe5825be1b41182b1c24 100644 (file)
 struct wm5110_priv {
        struct arizona_priv core;
        struct arizona_fll fll[2];
+
+       unsigned int in_value;
+       int in_pre_pending;
+       int in_post_pending;
+
+       unsigned int in_pga_cache[6];
 };
 
 static const struct wm_adsp_region wm5110_dsp1_regions[] = {
@@ -428,6 +434,127 @@ err:
        return ret;
 }
 
+static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_card *card = dapm->card;
+       int ret;
+
+       /*
+        * PGA Volume is also used as part of the enable sequence, so
+        * usage of it should be avoided whilst that is running.
+        */
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
+
+       mutex_unlock(&card->dapm_mutex);
+
+       return ret;
+}
+
+static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_card *card = dapm->card;
+       int ret;
+
+       /*
+        * PGA Volume is also used as part of the enable sequence, so
+        * usage of it should be avoided whilst that is running.
+        */
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
+
+       mutex_unlock(&card->dapm_mutex);
+
+       return ret;
+}
+
+static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       unsigned int reg, mask;
+       struct reg_sequence analog_seq[] = {
+               { 0x80, 0x3 },
+               { 0x35d, 0 },
+               { 0x80, 0x0 },
+       };
+
+       reg = ARIZONA_IN1L_CONTROL + ((w->shift ^ 0x1) * 4);
+       mask = ARIZONA_IN1L_PGA_VOL_MASK;
+
+       switch (event) {
+       case SND_SOC_DAPM_WILL_PMU:
+               wm5110->in_value |= 0x3 << ((w->shift ^ 0x1) * 2);
+               wm5110->in_pre_pending++;
+               wm5110->in_post_pending++;
+               return 0;
+       case SND_SOC_DAPM_PRE_PMU:
+               wm5110->in_pga_cache[w->shift] = snd_soc_read(codec, reg);
+
+               snd_soc_update_bits(codec, reg, mask,
+                                   0x40 << ARIZONA_IN1L_PGA_VOL_SHIFT);
+
+               wm5110->in_pre_pending--;
+               if (wm5110->in_pre_pending == 0) {
+                       analog_seq[1].def = wm5110->in_value;
+                       regmap_multi_reg_write_bypassed(arizona->regmap,
+                                                       analog_seq,
+                                                       ARRAY_SIZE(analog_seq));
+
+                       msleep(55);
+
+                       wm5110->in_value = 0;
+               }
+
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, reg, mask,
+                                   wm5110->in_pga_cache[w->shift]);
+
+               wm5110->in_post_pending--;
+               if (wm5110->in_post_pending == 0)
+                       regmap_multi_reg_write_bypassed(arizona->regmap,
+                                                       analog_seq,
+                                                       ARRAY_SIZE(analog_seq));
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int wm5110_in_ev(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+
+       switch (arizona->rev) {
+       case 0 ... 4:
+               if (arizona_input_analog(codec, w->shift))
+                       wm5110_in_analog_ev(w, kcontrol, event);
+
+               break;
+       default:
+               break;
+       }
+
+       return arizona_in_ev(w, kcontrol, event);
+}
+
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
@@ -454,18 +581,24 @@ SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
 SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]),
 SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]),
 
-SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
-                    ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
-                    ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
-                    ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
-                    ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
-                    ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
-                    ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+                        ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+                        ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+                        ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+                        ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
+                        ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
+                        ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+                        wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
 
 SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
 
@@ -896,29 +1029,35 @@ SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
 SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
-                  0, NULL, 0, arizona_in_ev,
+                  0, NULL, 0, wm5110_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                  SND_SOC_DAPM_WILL_PMU),
 SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
index 15bd547e3c84885751f86d8e6728e0a1d96a7788..4bcf5f8ece50f3681948a9fbc47b85400d9a8b51 100644 (file)
@@ -132,7 +132,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index b011253459af98f57fd87b574fa02164cf38830a..e4cc41e6c23e333cbb771d6f1da91c19c5ff6079 100644 (file)
@@ -452,7 +452,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
        int ret = 0;
 
        if (deemph > 1)
index b783743dc97e5a7e82699490aab28ca2e8380950..2aa23f1b9e3ca132c12e826d980b5154ffbe1478 100644 (file)
@@ -534,7 +534,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index 12e4435f00f85507340305442747119f8feb5208..9db00d53abe76f58be4e74a4b4e5342c3a19147d 100644 (file)
@@ -402,7 +402,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
index dbd88408861a21af9f3d68ecaf72294b3d47734e..056375339ea32948207723b1affd84ebdd0b1730 100644 (file)
@@ -201,7 +201,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int deemph = ucontrol->value.integer.value[0];
+       unsigned int deemph = ucontrol->value.integer.value[0];
 
        if (deemph > 1)
                return -EINVAL;
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
new file mode 100644 (file)
index 0000000..8782dfb
--- /dev/null
@@ -0,0 +1,1430 @@
+/*
+ * wm8998.c -- ALSA SoC Audio driver for WM8998 codecs
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm8998.h"
+
+struct wm8998_priv {
+       struct arizona_priv core;
+       struct arizona_fll fll[2];
+};
+
+static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       unsigned int val;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               val = snd_soc_read(codec, ARIZONA_ASRC_RATE1);
+               val &= ARIZONA_ASRC_RATE1_MASK;
+               val >>= ARIZONA_ASRC_RATE1_SHIFT;
+
+               switch (val) {
+               case 0:
+               case 1:
+               case 2:
+                       val = snd_soc_read(codec,
+                                          ARIZONA_SAMPLE_RATE_1 + val);
+                       if (val >= 0x11) {
+                               dev_warn(codec->dev,
+                                        "Unsupported ASRC rate1 (%s)\n",
+                                        arizona_sample_rate_val_to_name(val));
+                       return -EINVAL;
+                       }
+                       break;
+               default:
+                       dev_err(codec->dev,
+                               "Illegal ASRC rate1 selector (0x%x)\n",
+                               val);
+                       return -EINVAL;
+               }
+
+               val = snd_soc_read(codec, ARIZONA_ASRC_RATE2);
+               val &= ARIZONA_ASRC_RATE2_MASK;
+               val >>= ARIZONA_ASRC_RATE2_SHIFT;
+
+               switch (val) {
+               case 8:
+               case 9:
+                       val -= 0x8;
+                       val = snd_soc_read(codec,
+                                          ARIZONA_ASYNC_SAMPLE_RATE_1 + val);
+                       if (val >= 0x11) {
+                               dev_warn(codec->dev,
+                                        "Unsupported ASRC rate2 (%s)\n",
+                                        arizona_sample_rate_val_to_name(val));
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       dev_err(codec->dev,
+                               "Illegal ASRC rate2 selector (0x%x)\n",
+                               val);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8998_in1mux_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = wm8998->core.arizona;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int mux, inmode;
+       unsigned int mode_val, src_val;
+
+       mux = ucontrol->value.enumerated.item[0];
+       if (mux > 1)
+               return -EINVAL;
+
+       /* L and R registers have same shift and mask */
+       inmode = arizona->pdata.inmode[2 * mux];
+       src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
+       if (inmode & ARIZONA_INMODE_SE)
+               src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
+
+       switch (arizona->pdata.inmode[0]) {
+       case ARIZONA_INMODE_DMIC:
+               if (mux)
+                       mode_val = 0;   /* B always analogue */
+               else
+                       mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
+
+               snd_soc_update_bits(codec, ARIZONA_IN1L_CONTROL,
+                                   ARIZONA_IN1_MODE_MASK, mode_val);
+
+               /* IN1A is digital so L and R must change together */
+               /* src_val setting same for both registers */
+               snd_soc_update_bits(codec,
+                                   ARIZONA_ADC_DIGITAL_VOLUME_1L,
+                                   ARIZONA_IN1L_SRC_MASK |
+                                   ARIZONA_IN1L_SRC_SE_MASK, src_val);
+               snd_soc_update_bits(codec,
+                                   ARIZONA_ADC_DIGITAL_VOLUME_1R,
+                                   ARIZONA_IN1R_SRC_MASK |
+                                   ARIZONA_IN1R_SRC_SE_MASK, src_val);
+               break;
+       default:
+               /* both analogue */
+               snd_soc_update_bits(codec,
+                                   e->reg,
+                                   ARIZONA_IN1L_SRC_MASK |
+                                   ARIZONA_IN1L_SRC_SE_MASK,
+                                   src_val);
+               break;
+       }
+
+       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                            ucontrol->value.enumerated.item[0],
+                                            e, NULL);
+}
+
+static int wm8998_in2mux_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = wm8998->core.arizona;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int mux, inmode, src_val, mode_val;
+
+       mux = ucontrol->value.enumerated.item[0];
+       if (mux > 1)
+               return -EINVAL;
+
+       inmode = arizona->pdata.inmode[1 + (2 * mux)];
+       if (inmode & ARIZONA_INMODE_DMIC)
+               mode_val = 1 << ARIZONA_IN2_MODE_SHIFT;
+       else
+               mode_val = 0;
+
+       src_val = mux << ARIZONA_IN2L_SRC_SHIFT;
+       if (inmode & ARIZONA_INMODE_SE)
+               src_val |= 1 << ARIZONA_IN2L_SRC_SE_SHIFT;
+
+       snd_soc_update_bits(codec, ARIZONA_IN2L_CONTROL,
+                           ARIZONA_IN2_MODE_MASK, mode_val);
+
+       snd_soc_update_bits(codec, ARIZONA_ADC_DIGITAL_VOLUME_2L,
+                           ARIZONA_IN2L_SRC_MASK | ARIZONA_IN2L_SRC_SE_MASK,
+                           src_val);
+
+       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                            ucontrol->value.enumerated.item[0],
+                                            e, NULL);
+}
+
+static const char * const wm8998_inmux_texts[] = {
+       "A",
+       "B",
+};
+
+static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
+                                 ARIZONA_ADC_DIGITAL_VOLUME_1L,
+                                 ARIZONA_IN1L_SRC_SHIFT,
+                                 wm8998_inmux_texts);
+
+static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
+                                 ARIZONA_ADC_DIGITAL_VOLUME_1R,
+                                 ARIZONA_IN1R_SRC_SHIFT,
+                                 wm8998_inmux_texts);
+
+static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
+                                 ARIZONA_ADC_DIGITAL_VOLUME_2L,
+                                 ARIZONA_IN2L_SRC_SHIFT,
+                                 wm8998_inmux_texts);
+
+static const struct snd_kcontrol_new wm8998_in1mux[2] = {
+       SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
+                         snd_soc_dapm_get_enum_double, wm8998_in1mux_put),
+       SOC_DAPM_ENUM_EXT("IN1R Mux", wm8998_in1muxr_enum,
+                         snd_soc_dapm_get_enum_double, wm8998_in1mux_put),
+};
+
+static const struct snd_kcontrol_new wm8998_in2mux =
+       SOC_DAPM_ENUM_EXT("IN2 Mux", wm8998_in2mux_enum,
+                         snd_soc_dapm_get_enum_double, wm8998_in2mux_put);
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define WM8998_NG_SRC(name, base) \
+       SOC_SINGLE(name " NG HPOUTL Switch",  base,  0, 1, 0), \
+       SOC_SINGLE(name " NG HPOUTR Switch",  base,  1, 1, 0), \
+       SOC_SINGLE(name " NG LINEOUTL Switch",  base,  2, 1, 0), \
+       SOC_SINGLE(name " NG LINEOUTR Switch",  base,  3, 1, 0), \
+       SOC_SINGLE(name " NG EPOUT Switch",   base,  4, 1, 0), \
+       SOC_SINGLE(name " NG SPKOUTL Switch",  base,  6, 1, 0), \
+       SOC_SINGLE(name " NG SPKOUTR Switch",  base,  7, 1, 0)
+
+static const struct snd_kcontrol_new wm8998_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+                    ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+                    ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
+                    ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+          ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+          ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2 HPF Switch", ARIZONA_IN2L_CONTROL,
+          ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+              ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+              ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+              ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_GAINMUX_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+ARIZONA_GAINMUX_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+                  ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+ARIZONA_MIXER_CONTROLS("HPOUTL", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUTR", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LINEOUTL", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LINEOUTR", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDATL", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDATR", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_DOUBLE_R("HPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+            ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("LINEOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+            ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+            ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+            ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+            ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+                ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("LINEOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+                ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+                ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+                ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+                ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+
+SOC_DOUBLE("SPKDAT Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+          ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+          ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+              ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM8998_NG_SRC("HPOUTL", ARIZONA_NOISE_GATE_SELECT_1L),
+WM8998_NG_SRC("HPOUTR", ARIZONA_NOISE_GATE_SELECT_1R),
+WM8998_NG_SRC("LINEOUTL", ARIZONA_NOISE_GATE_SELECT_2L),
+WM8998_NG_SRC("LINEOUTR", ARIZONA_NOISE_GATE_SELECT_2R),
+WM8998_NG_SRC("EPOUT",  ARIZONA_NOISE_GATE_SELECT_3L),
+WM8998_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
+WM8998_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
+WM8998_NG_SRC("SPKDATL", ARIZONA_NOISE_GATE_SELECT_5L),
+WM8998_NG_SRC("SPKDATR", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_GAINMUX_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_GAINMUX_CONTROLS("SPDIFTX1", ARIZONA_SPDIFTX1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SPDIFTX2", ARIZONA_SPDIFTX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MUX_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3,  ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDATL, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDATR, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(SPD1TX1, ARIZONA_SPDIFTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SPD1TX2, ARIZONA_SPDIFTX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+static const char * const wm8998_aec_loopback_texts[] = {
+       "HPOUTL", "HPOUTR", "LINEOUTL", "LINEOUTR", "EPOUT",
+       "SPKOUTL", "SPKOUTR", "SPKDATL", "SPKDATR",
+};
+
+static const unsigned int wm8998_aec_loopback_values[] = {
+       0, 1, 2, 3, 4, 6, 7, 8, 9,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
+                                       ARIZONA_DAC_AEC_CONTROL_1,
+                                       ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                                       wm8998_aec_loopback_texts,
+                                       wm8998_aec_loopback_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
+                                       ARIZONA_DAC_AEC_CONTROL_2,
+                                       ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                                       wm8998_aec_loopback_texts,
+                                       wm8998_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
+       SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback),
+       SOC_DAPM_ENUM("AEC2 Loopback", wm8998_aec2_loopback),
+};
+
+static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+                   ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1AL"),
+SND_SOC_DAPM_INPUT("IN1AR"),
+SND_SOC_DAPM_INPUT("IN1BL"),
+SND_SOC_DAPM_INPUT("IN1BR"),
+SND_SOC_DAPM_INPUT("IN2A"),
+SND_SOC_DAPM_INPUT("IN2B"),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &wm8998_in1mux[0]),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &wm8998_in1mux[1]),
+SND_SOC_DAPM_MUX("IN2 Mux", SND_SOC_NOPM, 0, 0, &wm8998_in2mux),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2 PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+                0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+                0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+                  NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+                  NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+                  NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+                  NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC1 Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+                      ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+                      &wm8998_aec_loopback_mux[0]),
+
+SND_SOC_DAPM_MUX("AEC2 Loopback", ARIZONA_DAC_AEC_CONTROL_2,
+                      ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+                      &wm8998_aec_loopback_mux[1]),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+                    ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+                    ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+                   ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+                   ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPD1TX1", ARIZONA_SPD1_TX_CONTROL,
+                  ARIZONA_SPD1_VAL1_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPD1TX2", ARIZONA_SPD1_TX_CONTROL,
+                  ARIZONA_SPD1_VAL2_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPD1", ARIZONA_SPD1_TX_CONTROL,
+                    ARIZONA_SPD1_ENA_SHIFT, 0, NULL, 0),
+
+ARIZONA_MUX_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MUX_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MUX_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MUX_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MUX_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MUX_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUTL"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUTR"),
+ARIZONA_MIXER_WIDGETS(OUT2L, "LINEOUTL"),
+ARIZONA_MIXER_WIDGETS(OUT2R, "LINEOUTR"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+ARIZONA_MIXER_WIDGETS(SPKDATL, "SPKDATL"),
+ARIZONA_MIXER_WIDGETS(SPKDATR, "SPKDATR"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MUX_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MUX_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MUX_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MUX_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MUX_WIDGETS(SLIMTX6, "SLIMTX6"),
+
+ARIZONA_MUX_WIDGETS(SPD1TX1, "SPDIFTX1"),
+ARIZONA_MUX_WIDGETS(SPD1TX2, "SPDIFTX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+SND_SOC_DAPM_OUTPUT("EPOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKDATL"),
+SND_SOC_DAPM_OUTPUT("SPKDATR"),
+SND_SOC_DAPM_OUTPUT("SPDIF"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)       \
+       { name, "Tone Generator 1", "Tone Generator 1" }, \
+       { name, "Tone Generator 2", "Tone Generator 2" }, \
+       { name, "Haptics", "HAPTICS" }, \
+       { name, "AEC", "AEC1 Loopback" }, \
+       { name, "AEC2", "AEC2 Loopback" }, \
+       { name, "IN1L", "IN1L PGA" }, \
+       { name, "IN1R", "IN1R PGA" }, \
+       { name, "IN2L", "IN2 PGA" }, \
+       { name, "AIF1RX1", "AIF1RX1" }, \
+       { name, "AIF1RX2", "AIF1RX2" }, \
+       { name, "AIF1RX3", "AIF1RX3" }, \
+       { name, "AIF1RX4", "AIF1RX4" }, \
+       { name, "AIF1RX5", "AIF1RX5" }, \
+       { name, "AIF1RX6", "AIF1RX6" }, \
+       { name, "AIF2RX1", "AIF2RX1" }, \
+       { name, "AIF2RX2", "AIF2RX2" }, \
+       { name, "AIF2RX3", "AIF2RX3" }, \
+       { name, "AIF2RX4", "AIF2RX4" }, \
+       { name, "AIF2RX5", "AIF2RX5" }, \
+       { name, "AIF2RX6", "AIF2RX6" }, \
+       { name, "AIF3RX1", "AIF3RX1" }, \
+       { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "EQ1", "EQ1" }, \
+       { name, "EQ2", "EQ2" }, \
+       { name, "EQ3", "EQ3" }, \
+       { name, "EQ4", "EQ4" }, \
+       { name, "DRC1L", "DRC1L" }, \
+       { name, "DRC1R", "DRC1R" }, \
+       { name, "LHPF1", "LHPF1" }, \
+       { name, "LHPF2", "LHPF2" }, \
+       { name, "LHPF3", "LHPF3" }, \
+       { name, "LHPF4", "LHPF4" }, \
+       { name, "ASRC1L", "ASRC1L" }, \
+       { name, "ASRC1R", "ASRC1R" }, \
+       { name, "ASRC2L", "ASRC2L" }, \
+       { name, "ASRC2R", "ASRC2R" }, \
+       { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+       { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+       { name, "ISRC1DEC3", "ISRC1DEC3" }, \
+       { name, "ISRC1DEC4", "ISRC1DEC4" }, \
+       { name, "ISRC1INT1", "ISRC1INT1" }, \
+       { name, "ISRC1INT2", "ISRC1INT2" }, \
+       { name, "ISRC1INT3", "ISRC1INT3" }, \
+       { name, "ISRC1INT4", "ISRC1INT4" }, \
+       { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+       { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+       { name, "ISRC2INT1", "ISRC2INT1" }, \
+       { name, "ISRC2INT2", "ISRC2INT2" }
+
+static const struct snd_soc_dapm_route wm8998_dapm_routes[] = {
+       { "AIF2 Capture", NULL, "DBVDD2" },
+       { "AIF2 Playback", NULL, "DBVDD2" },
+
+       { "AIF3 Capture", NULL, "DBVDD3" },
+       { "AIF3 Playback", NULL, "DBVDD3" },
+
+       { "OUT1L", NULL, "CPVDD" },
+       { "OUT1R", NULL, "CPVDD" },
+       { "OUT2L", NULL, "CPVDD" },
+       { "OUT2R", NULL, "CPVDD" },
+       { "OUT3",  NULL, "CPVDD" },
+
+       { "OUT4L", NULL, "SPKVDDL" },
+       { "OUT4R", NULL, "SPKVDDR" },
+
+       { "OUT1L", NULL, "SYSCLK" },
+       { "OUT1R", NULL, "SYSCLK" },
+       { "OUT2L", NULL, "SYSCLK" },
+       { "OUT2R", NULL, "SYSCLK" },
+       { "OUT3",  NULL, "SYSCLK" },
+       { "OUT4L", NULL, "SYSCLK" },
+       { "OUT4R", NULL, "SYSCLK" },
+       { "OUT5L", NULL, "SYSCLK" },
+       { "OUT5R", NULL, "SYSCLK" },
+
+       { "IN1AL", NULL, "SYSCLK" },
+       { "IN1AR", NULL, "SYSCLK" },
+       { "IN1BL", NULL, "SYSCLK" },
+       { "IN1BR", NULL, "SYSCLK" },
+       { "IN2A", NULL, "SYSCLK" },
+       { "IN2B", NULL, "SYSCLK" },
+
+       { "SPD1", NULL, "SYSCLK" },
+       { "SPD1", NULL, "SPD1TX1" },
+       { "SPD1", NULL, "SPD1TX2" },
+
+       { "MICBIAS1", NULL, "MICVDD" },
+       { "MICBIAS2", NULL, "MICVDD" },
+       { "MICBIAS3", NULL, "MICVDD" },
+
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
+       { "Tone Generator 1", NULL, "TONE" },
+       { "Tone Generator 2", NULL, "TONE" },
+
+       { "AIF1 Capture", NULL, "AIF1TX1" },
+       { "AIF1 Capture", NULL, "AIF1TX2" },
+       { "AIF1 Capture", NULL, "AIF1TX3" },
+       { "AIF1 Capture", NULL, "AIF1TX4" },
+       { "AIF1 Capture", NULL, "AIF1TX5" },
+       { "AIF1 Capture", NULL, "AIF1TX6" },
+
+       { "AIF1RX1", NULL, "AIF1 Playback" },
+       { "AIF1RX2", NULL, "AIF1 Playback" },
+       { "AIF1RX3", NULL, "AIF1 Playback" },
+       { "AIF1RX4", NULL, "AIF1 Playback" },
+       { "AIF1RX5", NULL, "AIF1 Playback" },
+       { "AIF1RX6", NULL, "AIF1 Playback" },
+
+       { "AIF2 Capture", NULL, "AIF2TX1" },
+       { "AIF2 Capture", NULL, "AIF2TX2" },
+       { "AIF2 Capture", NULL, "AIF2TX3" },
+       { "AIF2 Capture", NULL, "AIF2TX4" },
+       { "AIF2 Capture", NULL, "AIF2TX5" },
+       { "AIF2 Capture", NULL, "AIF2TX6" },
+
+       { "AIF2RX1", NULL, "AIF2 Playback" },
+       { "AIF2RX2", NULL, "AIF2 Playback" },
+       { "AIF2RX3", NULL, "AIF2 Playback" },
+       { "AIF2RX4", NULL, "AIF2 Playback" },
+       { "AIF2RX5", NULL, "AIF2 Playback" },
+       { "AIF2RX6", NULL, "AIF2 Playback" },
+
+       { "AIF3 Capture", NULL, "AIF3TX1" },
+       { "AIF3 Capture", NULL, "AIF3TX2" },
+
+       { "AIF3RX1", NULL, "AIF3 Playback" },
+       { "AIF3RX2", NULL, "AIF3 Playback" },
+
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+
+       { "SLIMRX3", NULL, "Slim2 Playback" },
+       { "SLIMRX4", NULL, "Slim2 Playback" },
+
+       { "AIF1 Playback", NULL, "SYSCLK" },
+       { "AIF2 Playback", NULL, "SYSCLK" },
+       { "AIF3 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+
+       { "AIF1 Capture", NULL, "SYSCLK" },
+       { "AIF2 Capture", NULL, "SYSCLK" },
+       { "AIF3 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+
+       { "IN1L Mux", "A", "IN1AL" },
+       { "IN1R Mux", "A", "IN1AR" },
+       { "IN1L Mux", "B", "IN1BL" },
+       { "IN1R Mux", "B", "IN1BR" },
+
+       { "IN2 Mux", "A", "IN2A" },
+       { "IN2 Mux", "B", "IN2B" },
+
+       { "IN1L PGA", NULL, "IN1L Mux" },
+       { "IN1R PGA", NULL, "IN1R Mux" },
+       { "IN2 PGA",  NULL, "IN2 Mux" },
+
+       ARIZONA_MIXER_ROUTES("OUT1L", "HPOUTL"),
+       ARIZONA_MIXER_ROUTES("OUT1R", "HPOUTR"),
+       ARIZONA_MIXER_ROUTES("OUT2L", "LINEOUTL"),
+       ARIZONA_MIXER_ROUTES("OUT2R", "LINEOUTR"),
+       ARIZONA_MIXER_ROUTES("OUT3",  "EPOUT"),
+
+       ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+       ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+       ARIZONA_MIXER_ROUTES("OUT5L", "SPKDATL"),
+       ARIZONA_MIXER_ROUTES("OUT5R", "SPKDATR"),
+
+       ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+       ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+       ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+       ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+       ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+       ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+       ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+       ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+
+       ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+       ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+       ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+       ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+       ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+       ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+       ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+       ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+       ARIZONA_MUX_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MUX_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MUX_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MUX_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MUX_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MUX_ROUTES("SLIMTX6", "SLIMTX6"),
+
+       ARIZONA_MUX_ROUTES("SPD1TX1", "SPDIFTX1"),
+       ARIZONA_MUX_ROUTES("SPD1TX2", "SPDIFTX2"),
+
+       ARIZONA_MUX_ROUTES("EQ1", "EQ1"),
+       ARIZONA_MUX_ROUTES("EQ2", "EQ2"),
+       ARIZONA_MUX_ROUTES("EQ3", "EQ3"),
+       ARIZONA_MUX_ROUTES("EQ4", "EQ4"),
+
+       ARIZONA_MUX_ROUTES("DRC1L", "DRC1L"),
+       ARIZONA_MUX_ROUTES("DRC1R", "DRC1R"),
+
+       ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+       ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+       ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+       ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+       ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+       ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+       ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+       ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+       ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+       ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+       ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+       ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+       ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+       ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+       ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+       ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+       { "AEC1 Loopback", "HPOUTL", "OUT1L" },
+       { "AEC1 Loopback", "HPOUTR", "OUT1R" },
+       { "AEC2 Loopback", "HPOUTL", "OUT1L" },
+       { "AEC2 Loopback", "HPOUTR", "OUT1R" },
+       { "HPOUTL", NULL, "OUT1L" },
+       { "HPOUTR", NULL, "OUT1R" },
+
+       { "AEC1 Loopback", "LINEOUTL", "OUT2L" },
+       { "AEC1 Loopback", "LINEOUTR", "OUT2R" },
+       { "AEC2 Loopback", "LINEOUTL", "OUT2L" },
+       { "AEC2 Loopback", "LINEOUTR", "OUT2R" },
+       { "LINEOUTL", NULL, "OUT2L" },
+       { "LINEOUTR", NULL, "OUT2R" },
+
+       { "AEC1 Loopback", "EPOUT", "OUT3" },
+       { "AEC2 Loopback", "EPOUT", "OUT3" },
+       { "EPOUT", NULL, "OUT3" },
+
+       { "AEC1 Loopback", "SPKOUTL", "OUT4L" },
+       { "AEC2 Loopback", "SPKOUTL", "OUT4L" },
+       { "SPKOUTLN", NULL, "OUT4L" },
+       { "SPKOUTLP", NULL, "OUT4L" },
+
+       { "AEC1 Loopback", "SPKOUTR", "OUT4R" },
+       { "AEC2 Loopback", "SPKOUTR", "OUT4R" },
+       { "SPKOUTRN", NULL, "OUT4R" },
+       { "SPKOUTRP", NULL, "OUT4R" },
+
+       { "SPDIF", NULL, "SPD1" },
+
+       { "AEC1 Loopback", "SPKDATL", "OUT5L" },
+       { "AEC1 Loopback", "SPKDATR", "OUT5R" },
+       { "AEC2 Loopback", "SPKDATL", "OUT5L" },
+       { "AEC2 Loopback", "SPKDATR", "OUT5R" },
+       { "SPKDATL", NULL, "OUT5L" },
+       { "SPKDATR", NULL, "OUT5R" },
+
+       { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
+};
+
+#define WM8998_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8998_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8998_dai[] = {
+       {
+               .name = "wm8998-aif1",
+               .id = 1,
+               .base = ARIZONA_AIF1_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = WM8998_RATES,
+                       .formats = WM8998_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = WM8998_RATES,
+                        .formats = WM8998_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "wm8998-aif2",
+               .id = 2,
+               .base = ARIZONA_AIF2_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = WM8998_RATES,
+                       .formats = WM8998_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = WM8998_RATES,
+                        .formats = WM8998_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "wm8998-aif3",
+               .id = 3,
+               .base = ARIZONA_AIF3_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8998_RATES,
+                       .formats = WM8998_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8998_RATES,
+                        .formats = WM8998_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+               .symmetric_samplebits = 1,
+       },
+       {
+               .name = "wm8998-slim1",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8998_RATES,
+                       .formats = WM8998_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 4,
+                        .rates = WM8998_RATES,
+                        .formats = WM8998_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm8998-slim2",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8998_RATES,
+                       .formats = WM8998_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8998_RATES,
+                        .formats = WM8998_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+};
+
+static int wm8998_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
+
+       switch (fll_id) {
+       case WM8998_FLL1:
+               return arizona_set_fll(&wm8998->fll[0], source, Fref, Fout);
+       case WM8998_FLL2:
+               return arizona_set_fll(&wm8998->fll[1], source, Fref, Fout);
+       case WM8998_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm8998->fll[0], source, Fref,
+                                             Fout);
+       case WM8998_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm8998->fll[1], source, Fref,
+                                             Fout);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int wm8998_codec_probe(struct snd_soc_codec *codec)
+{
+       struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+       priv->core.arizona->dapm = dapm;
+
+       arizona_init_spk(codec);
+       arizona_init_gpio(codec);
+
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+
+       return 0;
+}
+
+static int wm8998_codec_remove(struct snd_soc_codec *codec)
+{
+       struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->core.arizona->dapm = NULL;
+
+       return 0;
+}
+
+#define WM8998_DIG_VU 0x0200
+
+static unsigned int wm8998_digital_vu[] = {
+       ARIZONA_DAC_DIGITAL_VOLUME_1L,
+       ARIZONA_DAC_DIGITAL_VOLUME_1R,
+       ARIZONA_DAC_DIGITAL_VOLUME_2L,
+       ARIZONA_DAC_DIGITAL_VOLUME_2R,
+       ARIZONA_DAC_DIGITAL_VOLUME_3L,
+       ARIZONA_DAC_DIGITAL_VOLUME_4L,
+       ARIZONA_DAC_DIGITAL_VOLUME_4R,
+       ARIZONA_DAC_DIGITAL_VOLUME_5L,
+       ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static struct regmap *wm8998_get_regmap(struct device *dev)
+{
+       struct wm8998_priv *priv = dev_get_drvdata(dev);
+
+       return priv->core.arizona->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
+       .probe = wm8998_codec_probe,
+       .remove = wm8998_codec_remove,
+       .get_regmap = wm8998_get_regmap,
+
+       .idle_bias_off = true,
+
+       .set_sysclk = arizona_set_sysclk,
+       .set_pll = wm8998_set_fll,
+
+       .controls = wm8998_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8998_snd_controls),
+       .dapm_widgets = wm8998_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8998_dapm_widgets),
+       .dapm_routes = wm8998_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes),
+};
+
+static int wm8998_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct wm8998_priv *wm8998;
+       int i;
+
+       wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv),
+                             GFP_KERNEL);
+       if (!wm8998)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, wm8998);
+
+       wm8998->core.arizona = arizona;
+       wm8998->core.num_inputs = 3;    /* IN1L, IN1R, IN2 */
+
+       for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++)
+               wm8998->fll[i].vco_mult = 1;
+
+       arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+                        &wm8998->fll[0]);
+       arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+                        &wm8998->fll[1]);
+
+       for (i = 0; i < ARRAY_SIZE(wm8998_dai); i++)
+               arizona_init_dai(&wm8998->core, i);
+
+       /* Latch volume update bits */
+       for (i = 0; i < ARRAY_SIZE(wm8998_digital_vu); i++)
+               regmap_update_bits(arizona->regmap, wm8998_digital_vu[i],
+                                  WM8998_DIG_VU, WM8998_DIG_VU);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
+                                     wm8998_dai, ARRAY_SIZE(wm8998_dai));
+}
+
+static int wm8998_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver wm8998_codec_driver = {
+       .driver = {
+               .name = "wm8998-codec",
+       },
+       .probe = wm8998_probe,
+       .remove = wm8998_remove,
+};
+
+module_platform_driver(wm8998_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8998 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:wm8998-codec");
diff --git a/sound/soc/codecs/wm8998.h b/sound/soc/codecs/wm8998.h
new file mode 100644 (file)
index 0000000..1e86472
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * wm8998.h -- ALSA SoC Audio driver for WM8998 codecs
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.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 _WM8998_H
+#define _WM8998_H
+
+#include "arizona.h"
+
+#define WM8998_FLL1        1
+#define WM8998_FLL2        2
+#define WM8998_FLL1_REFCLK 3
+#define WM8998_FLL2_REFCLK 4
+
+#endif
index 7d45d98a861fccb65f32987e3760c2b74e487f9a..4495a40a94680600ff324bd035098ff3d73f594b 100644 (file)
@@ -80,12 +80,13 @@ struct davinci_mcasp {
 
        /* McASP specific data */
        int     tdm_slots;
+       u32     tdm_mask[2];
+       int     slot_width;
        u8      op_mode;
        u8      num_serializer;
        u8      *serial_dir;
        u8      version;
        u8      bclk_div;
-       u16     bclk_lrclk_ratio;
        int     streams;
        u32     irq_request[2];
        int     dma_request[2];
@@ -556,8 +557,21 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
                        mcasp->bclk_div = div;
                break;
 
-       case 2:         /* BCLK/LRCLK ratio */
-               mcasp->bclk_lrclk_ratio = div;
+       case 2: /*
+                * BCLK/LRCLK ratio descries how many bit-clock cycles
+                * fit into one frame. The clock ratio is given for a
+                * full period of data (for I2S format both left and
+                * right channels), so it has to be divided by number
+                * of tdm-slots (for I2S - divided by 2).
+                * Instead of storing this ratio, we calculate a new
+                * tdm_slot width by dividing the the ratio by the
+                * number of configured tdm slots.
+                */
+               mcasp->slot_width = div / mcasp->tdm_slots;
+               if (div % mcasp->tdm_slots)
+                       dev_warn(mcasp->dev,
+                                "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
+                                __func__, div, mcasp->tdm_slots);
                break;
 
        default:
@@ -596,12 +610,92 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        return 0;
 }
 
+/* All serializers must have equal number of channels */
+static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
+                                      int serializers)
+{
+       struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
+       unsigned int *list = (unsigned int *) cl->list;
+       int slots = mcasp->tdm_slots;
+       int i, count = 0;
+
+       if (mcasp->tdm_mask[stream])
+               slots = hweight32(mcasp->tdm_mask[stream]);
+
+       for (i = 2; i <= slots; i++)
+               list[count++] = i;
+
+       for (i = 2; i <= serializers; i++)
+               list[count++] = i*slots;
+
+       cl->count = count;
+
+       return 0;
+}
+
+static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
+{
+       int rx_serializers = 0, tx_serializers = 0, ret, i;
+
+       for (i = 0; i < mcasp->num_serializer; i++)
+               if (mcasp->serial_dir[i] == TX_MODE)
+                       tx_serializers++;
+               else if (mcasp->serial_dir[i] == RX_MODE)
+                       rx_serializers++;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
+                                         tx_serializers);
+       if (ret)
+               return ret;
+
+       ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
+                                         rx_serializers);
+
+       return ret;
+}
+
+
+static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
+                                     unsigned int tx_mask,
+                                     unsigned int rx_mask,
+                                     int slots, int slot_width)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+       dev_dbg(mcasp->dev,
+                "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
+                __func__, tx_mask, rx_mask, slots, slot_width);
+
+       if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
+               dev_err(mcasp->dev,
+                       "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
+                       tx_mask, rx_mask, slots);
+               return -EINVAL;
+       }
+
+       if (slot_width &&
+           (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
+               dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
+                       __func__, slot_width);
+               return -EINVAL;
+       }
+
+       mcasp->tdm_slots = slots;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask;
+       mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask;
+       mcasp->slot_width = slot_width;
+
+       return davinci_mcasp_set_ch_constraints(mcasp);
+}
+
 static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
-                                      int word_length)
+                                      int sample_width)
 {
        u32 fmt;
-       u32 tx_rotate = (word_length / 4) & 0x7;
-       u32 mask = (1ULL << word_length) - 1;
+       u32 tx_rotate = (sample_width / 4) & 0x7;
+       u32 mask = (1ULL << sample_width) - 1;
+       u32 slot_width = sample_width;
+
        /*
         * For captured data we should not rotate, inversion and masking is
         * enoguh to get the data to the right position:
@@ -614,28 +708,23 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
        u32 rx_rotate = 0;
 
        /*
-        * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv()
-        * callback, take it into account here. That allows us to for example
-        * send 32 bits per channel to the codec, while only 16 of them carry
-        * audio payload.
-        * The clock ratio is given for a full period of data (for I2S format
-        * both left and right channels), so it has to be divided by number of
-        * tdm-slots (for I2S - divided by 2).
+        * Setting the tdm slot width either with set_clkdiv() or
+        * set_tdm_slot() allows us to for example send 32 bits per
+        * channel to the codec, while only 16 of them carry audio
+        * payload.
         */
-       if (mcasp->bclk_lrclk_ratio) {
-               u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
-
+       if (mcasp->slot_width) {
                /*
-                * When we have more bclk then it is needed for the data, we
-                * need to use the rotation to move the received samples to have
-                * correct alignment.
+                * When we have more bclk then it is needed for the
+                * data, we need to use the rotation to move the
+                * received samples to have correct alignment.
                 */
-               rx_rotate = (slot_length - word_length) / 4;
-               word_length = slot_length;
+               slot_width = mcasp->slot_width;
+               rx_rotate = (slot_width - sample_width) / 4;
        }
 
        /* mapping of the XSSZ bit-field as described in the datasheet */
-       fmt = (word_length >> 1) - 1;
+       fmt = (slot_width >> 1) - 1;
 
        if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
@@ -776,33 +865,50 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
 
        /*
         * If more than one serializer is needed, then use them with
-        * their specified tdm_slots count. Otherwise, one serializer
-        * can cope with the transaction using as many slots as channels
-        * in the stream, requires channels symmetry
+        * all the specified tdm_slots. Otherwise, one serializer can
+        * cope with the transaction using just as many slots as there
+        * are channels in the stream.
         */
-       active_serializers = (channels + total_slots - 1) / total_slots;
-       if (active_serializers == 1)
-               active_slots = channels;
-       else
-               active_slots = total_slots;
-
-       for (i = 0; i < active_slots; i++)
-               mask |= (1 << i);
+       if (mcasp->tdm_mask[stream]) {
+               active_slots = hweight32(mcasp->tdm_mask[stream]);
+               active_serializers = (channels + active_slots - 1) /
+                       active_slots;
+               if (active_serializers == 1) {
+                       active_slots = channels;
+                       for (i = 0; i < total_slots; i++) {
+                               if ((1 << i) & mcasp->tdm_mask[stream]) {
+                                       mask |= (1 << i);
+                                       if (--active_slots <= 0)
+                                               break;
+                               }
+                       }
+               }
+       } else {
+               active_serializers = (channels + total_slots - 1) / total_slots;
+               if (active_serializers == 1)
+                       active_slots = channels;
+               else
+                       active_slots = total_slots;
 
+               for (i = 0; i < active_slots; i++)
+                       mask |= (1 << i);
+       }
        mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
 
        if (!mcasp->dat_port)
                busel = TXSEL;
 
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-                      FSXMOD(total_slots), FSXMOD(0x1FF));
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-                      FSRMOD(total_slots), FSRMOD(0x1FF));
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                              FSXMOD(total_slots), FSXMOD(0x1FF));
+       } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+                              FSRMOD(total_slots), FSRMOD(0x1FF));
+       }
 
        return 0;
 }
@@ -922,6 +1028,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                int sbits = params_width(params);
                int ppm, div;
 
+               if (mcasp->slot_width)
+                       sbits = mcasp->slot_width;
+
                div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots,
                                                 &ppm);
                if (ppm)
@@ -1027,6 +1136,9 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
        struct snd_interval range;
        int i;
 
+       if (rd->mcasp->slot_width)
+               sbits = rd->mcasp->slot_width;
+
        snd_interval_any(&range);
        range.empty = 1;
 
@@ -1069,10 +1181,14 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
 
        for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
                if (snd_mask_test(fmt, i)) {
-                       uint bclk_freq = snd_pcm_format_width(i)*slots*rate;
+                       uint sbits = snd_pcm_format_width(i);
                        int ppm;
 
-                       davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+                       if (rd->mcasp->slot_width)
+                               sbits = rd->mcasp->slot_width;
+
+                       davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate,
+                                                  &ppm);
                        if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
                                snd_mask_set(&nfmt, i);
                                count++;
@@ -1094,6 +1210,10 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                        &mcasp->ruledata[substream->stream];
        u32 max_channels = 0;
        int i, dir;
+       int tdm_slots = mcasp->tdm_slots;
+
+       if (mcasp->tdm_mask[substream->stream])
+               tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
 
        mcasp->substreams[substream->stream] = substream;
 
@@ -1114,7 +1234,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                        max_channels++;
        }
        ruledata->serializers = max_channels;
-       max_channels *= mcasp->tdm_slots;
+       max_channels *= tdm_slots;
        /*
         * If the already active stream has less channels than the calculated
         * limnit based on the seirializers * tdm_slots, we need to use that as
@@ -1124,15 +1244,25 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
         */
        if (mcasp->channels && mcasp->channels < max_channels)
                max_channels = mcasp->channels;
+       /*
+        * But we can always allow channels upto the amount of
+        * the available tdm_slots.
+        */
+       if (max_channels < tdm_slots)
+               max_channels = tdm_slots;
 
        snd_pcm_hw_constraint_minmax(substream->runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS,
                                     2, max_channels);
 
-       if (mcasp->chconstr[substream->stream].count)
-               snd_pcm_hw_constraint_list(substream->runtime,
-                                          0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                          &mcasp->chconstr[substream->stream]);
+       snd_pcm_hw_constraint_list(substream->runtime,
+                                  0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &mcasp->chconstr[substream->stream]);
+
+       if (mcasp->slot_width)
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                            8, mcasp->slot_width);
 
        /*
         * If we rely on implicit BCLK divider setting we should
@@ -1184,6 +1314,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_fmt        = davinci_mcasp_set_dai_fmt,
        .set_clkdiv     = davinci_mcasp_set_clkdiv,
        .set_sysclk     = davinci_mcasp_set_sysclk,
+       .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
 };
 
 static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
@@ -1514,59 +1645,6 @@ nodata:
        return  pdata;
 }
 
-/* All serializers must have equal number of channels */
-static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp,
-                                      struct snd_pcm_hw_constraint_list *cl,
-                                      int serializers)
-{
-       unsigned int *list;
-       int i, count = 0;
-
-       if (serializers <= 1)
-               return 0;
-
-       list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
-                           (mcasp->tdm_slots + serializers - 2),
-                           GFP_KERNEL);
-       if (!list)
-               return -ENOMEM;
-
-       for (i = 2; i <= mcasp->tdm_slots; i++)
-               list[count++] = i;
-
-       for (i = 2; i <= serializers; i++)
-               list[count++] = i*mcasp->tdm_slots;
-
-       cl->count = count;
-       cl->list = list;
-
-       return 0;
-}
-
-
-static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp)
-{
-       int rx_serializers = 0, tx_serializers = 0, ret, i;
-
-       for (i = 0; i < mcasp->num_serializer; i++)
-               if (mcasp->serial_dir[i] == TX_MODE)
-                       tx_serializers++;
-               else if (mcasp->serial_dir[i] == RX_MODE)
-                       rx_serializers++;
-
-       ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-                                                 SNDRV_PCM_STREAM_PLAYBACK],
-                                         tx_serializers);
-       if (ret)
-               return ret;
-
-       ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[
-                                                 SNDRV_PCM_STREAM_CAPTURE],
-                                         rx_serializers);
-
-       return ret;
-}
-
 enum {
        PCM_EDMA,
        PCM_SDMA,
@@ -1783,7 +1861,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
        }
 
-       ret = davinci_mcasp_init_ch_constraints(mcasp);
+       /* Allocate memory for long enough list for all possible
+        * scenarios. Maximum number tdm slots is 32 and there cannot
+        * be more serializers than given in the configuration.  The
+        * serializer directions could be taken into account, but it
+        * would make code much more complex and save only couple of
+        * bytes.
+        */
+       mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
+               devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
+                            (32 + mcasp->num_serializer - 2),
+                            GFP_KERNEL);
+
+       mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
+               devm_kzalloc(mcasp->dev, sizeof(unsigned int) *
+                            (32 + mcasp->num_serializer - 2),
+                            GFP_KERNEL);
+
+       if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
+           !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list)
+               return -ENOMEM;
+
+       ret = davinci_mcasp_set_ch_constraints(mcasp);
        if (ret)
                goto err;
 
index ba34252b7bba4fdd8d1b7c58a313b490c14aa329..6e6a70c5c2bdba8349e4652e53a672c7fb40d74e 100644 (file)
@@ -282,23 +282,25 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 
        config->sample_rate = params_rate(params);
 
-       if (dev->i2s_clk_cfg) {
-               ret = dev->i2s_clk_cfg(config);
-               if (ret < 0) {
-                       dev_err(dev->dev, "runtime audio clk config fail\n");
-                       return ret;
-               }
-       } else {
-               u32 bitclk = config->sample_rate * config->data_width * 2;
-
-               ret = clk_set_rate(dev->clk, bitclk);
-               if (ret) {
-                       dev_err(dev->dev, "Can't set I2S clock rate: %d\n",
-                               ret);
-                       return ret;
+       if (dev->capability & DW_I2S_MASTER) {
+               if (dev->i2s_clk_cfg) {
+                       ret = dev->i2s_clk_cfg(config);
+                       if (ret < 0) {
+                               dev_err(dev->dev, "runtime audio clk config fail\n");
+                               return ret;
+                       }
+               } else {
+                       u32 bitclk = config->sample_rate *
+                                       config->data_width * 2;
+
+                       ret = clk_set_rate(dev->clk, bitclk);
+                       if (ret) {
+                               dev_err(dev->dev, "Can't set I2S clock rate: %d\n",
+                                       ret);
+                               return ret;
+                       }
                }
        }
-
        return 0;
 }
 
@@ -348,12 +350,43 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if (dev->capability & DW_I2S_SLAVE)
+                       ret = 0;
+               else
+                       ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (dev->capability & DW_I2S_MASTER)
+                       ret = 0;
+               else
+                       ret = -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBS_CFM:
+               ret = -EINVAL;
+               break;
+       default:
+               dev_dbg(dev->dev, "dwc : Invalid master/slave format\n");
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
 static struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .startup        = dw_i2s_startup,
        .shutdown       = dw_i2s_shutdown,
        .hw_params      = dw_i2s_hw_params,
        .prepare        = dw_i2s_prepare,
        .trigger        = dw_i2s_trigger,
+       .set_fmt        = dw_i2s_set_fmt,
 };
 
 static const struct snd_soc_component_driver dw_i2s_component = {
@@ -366,7 +399,8 @@ static int dw_i2s_suspend(struct snd_soc_dai *dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
 
-       clk_disable(dev->clk);
+       if (dev->capability & DW_I2S_MASTER)
+               clk_disable(dev->clk);
        return 0;
 }
 
@@ -374,7 +408,8 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
 
-       clk_enable(dev->clk);
+       if (dev->capability & DW_I2S_MASTER)
+               clk_enable(dev->clk);
        return 0;
 }
 
@@ -452,6 +487,14 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
                dw_i2s_dai->capture.rates = rates;
        }
 
+       if (COMP1_MODE_EN(comp1)) {
+               dev_dbg(dev->dev, "designware: i2s master mode supported\n");
+               dev->capability |= DW_I2S_MASTER;
+       } else {
+               dev_dbg(dev->dev, "designware: i2s slave mode supported\n");
+               dev->capability |= DW_I2S_SLAVE;
+       }
+
        return 0;
 }
 
@@ -538,6 +581,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
        struct snd_soc_dai_driver *dw_i2s_dai;
+       const char *clk_id;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev) {
@@ -559,32 +603,35 @@ static int dw_i2s_probe(struct platform_device *pdev)
                return PTR_ERR(dev->i2s_base);
 
        dev->dev = &pdev->dev;
+
        if (pdata) {
+               dev->capability = pdata->cap;
+               clk_id = NULL;
                ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
-               if (ret < 0)
-                       return ret;
+       } else {
+               clk_id = "i2sclk";
+               ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
+       }
+       if (ret < 0)
+               return ret;
 
-               dev->capability = pdata->cap;
-               dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
-               if (!dev->i2s_clk_cfg) {
-                       dev_err(&pdev->dev, "no clock configure method\n");
-                       return -ENODEV;
+       if (dev->capability & DW_I2S_MASTER) {
+               if (pdata) {
+                       dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+                       if (!dev->i2s_clk_cfg) {
+                               dev_err(&pdev->dev, "no clock configure method\n");
+                               return -ENODEV;
+                       }
                }
+               dev->clk = devm_clk_get(&pdev->dev, clk_id);
 
-               dev->clk = devm_clk_get(&pdev->dev, NULL);
-       } else {
-               ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
+               if (IS_ERR(dev->clk))
+                       return PTR_ERR(dev->clk);
+
+               ret = clk_prepare_enable(dev->clk);
                if (ret < 0)
                        return ret;
-
-               dev->clk = devm_clk_get(&pdev->dev, "i2sclk");
        }
-       if (IS_ERR(dev->clk))
-               return PTR_ERR(dev->clk);
-
-       ret = clk_prepare_enable(dev->clk);
-       if (ret < 0)
-               return ret;
 
        dev_set_drvdata(&pdev->dev, dev);
        ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component,
@@ -606,7 +653,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
        return 0;
 
 err_clk_disable:
-       clk_disable_unprepare(dev->clk);
+       if (dev->capability & DW_I2S_MASTER)
+               clk_disable_unprepare(dev->clk);
        return ret;
 }
 
@@ -614,7 +662,8 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       clk_disable_unprepare(dev->clk);
+       if (dev->capability & DW_I2S_MASTER)
+               clk_disable_unprepare(dev->clk);
 
        return 0;
 }
index 96f55ae75c719c87d1dcf9084ccc4e6a679a187f..1b05d1c5d9fd50fe32eb9b65f4da1340db9170e5 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
+#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
+#include <sound/ac97_codec.h>
+#endif
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
@@ -115,6 +118,11 @@ static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("DMIC", NULL),
 };
 
+static bool fsl_asoc_card_is_ac97(struct fsl_asoc_card_priv *priv)
+{
+       return priv->dai_fmt == SND_SOC_DAIFMT_AC97;
+}
+
 static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params)
 {
@@ -133,7 +141,9 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
         * set_bias_level(), bypass the remaining settings in hw_params().
         * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
         */
-       if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM)
+       if ((priv->card.set_bias_level &&
+            priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) ||
+           fsl_asoc_card_is_ac97(priv))
                return 0;
 
        /* Specific configurations of DAIs starts from here */
@@ -300,7 +310,7 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
        ext_port--;
 
        /*
-        * Use asynchronous mode (6 wires) for all cases.
+        * Use asynchronous mode (6 wires) for all cases except AC97.
         * If only 4 wires are needed, just set SSI into
         * synchronous mode and enable 4 PADs in IOMUX.
         */
@@ -346,15 +356,30 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
                break;
        default:
-               return -EINVAL;
+               if (!fsl_asoc_card_is_ac97(priv))
+                       return -EINVAL;
+       }
+
+       if (fsl_asoc_card_is_ac97(priv)) {
+               int_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
+                          IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                          IMX_AUDMUX_V2_PTCR_TCLKDIR;
+               ext_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
+                          IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+                          IMX_AUDMUX_V2_PTCR_TFSDIR;
        }
 
        /* Asynchronous mode can not be set along with RCLKDIR */
-       ret = imx_audmux_v2_configure_port(int_port, 0,
-                                          IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
-       if (ret) {
-               dev_err(dev, "audmux internal port setup failed\n");
-               return ret;
+       if (!fsl_asoc_card_is_ac97(priv)) {
+               unsigned int pdcr =
+                               IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port);
+
+               ret = imx_audmux_v2_configure_port(int_port, 0,
+                                                  pdcr);
+               if (ret) {
+                       dev_err(dev, "audmux internal port setup failed\n");
+                       return ret;
+               }
        }
 
        ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
@@ -364,11 +389,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
                return ret;
        }
 
-       ret = imx_audmux_v2_configure_port(ext_port, 0,
-                                          IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
-       if (ret) {
-               dev_err(dev, "audmux external port setup failed\n");
-               return ret;
+       if (!fsl_asoc_card_is_ac97(priv)) {
+               unsigned int pdcr =
+                               IMX_AUDMUX_V2_PDCR_RXDSEL(int_port);
+
+               ret = imx_audmux_v2_configure_port(ext_port, 0,
+                                                  pdcr);
+               if (ret) {
+                       dev_err(dev, "audmux external port setup failed\n");
+                       return ret;
+               }
        }
 
        ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
@@ -389,6 +419,23 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
        struct device *dev = card->dev;
        int ret;
 
+       if (fsl_asoc_card_is_ac97(priv)) {
+#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
+               struct snd_soc_codec *codec = card->rtd[0].codec;
+               struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+               /*
+                * Use slots 3/4 for S/PDIF so SSI won't try to enable
+                * other slots and send some samples there
+                * due to SLOTREQ bits for S/PDIF received from codec
+                */
+               snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
+                                    AC97_EA_SPSA_SLOT_MASK, AC97_EA_SPSA_3_4);
+#endif
+
+               return 0;
+       }
+
        ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
                                     codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
        if (ret) {
@@ -407,7 +454,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        struct platform_device *cpu_pdev;
        struct fsl_asoc_card_priv *priv;
        struct i2c_client *codec_dev;
-       struct clk *codec_clk;
        const char *codec_dai_name;
        u32 width;
        int ret;
@@ -420,9 +466,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        /* Give a chance to old DT binding */
        if (!cpu_np)
                cpu_np = of_parse_phandle(np, "ssi-controller", 0);
-       codec_np = of_parse_phandle(np, "audio-codec", 0);
-       if (!cpu_np || !codec_np) {
-               dev_err(&pdev->dev, "phandle missing or invalid\n");
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
                ret = -EINVAL;
                goto fail;
        }
@@ -434,22 +479,24 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       codec_dev = of_find_i2c_device_by_node(codec_np);
-       if (!codec_dev) {
-               dev_err(&pdev->dev, "failed to find codec platform device\n");
-               ret = -EINVAL;
-               goto fail;
-       }
+       codec_np = of_parse_phandle(np, "audio-codec", 0);
+       if (codec_np)
+               codec_dev = of_find_i2c_device_by_node(codec_np);
+       else
+               codec_dev = NULL;
 
        asrc_np = of_parse_phandle(np, "audio-asrc", 0);
        if (asrc_np)
                asrc_pdev = of_find_device_by_node(asrc_np);
 
        /* Get the MCLK rate only, and leave it controlled by CODEC drivers */
-       codec_clk = clk_get(&codec_dev->dev, NULL);
-       if (!IS_ERR(codec_clk)) {
-               priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
-               clk_put(codec_clk);
+       if (codec_dev) {
+               struct clk *codec_clk = clk_get(&codec_dev->dev, NULL);
+
+               if (!IS_ERR(codec_clk)) {
+                       priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
+                       clk_put(codec_clk);
+               }
        }
 
        /* Default sample rate and format, will be updated in hw_params() */
@@ -486,12 +533,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
                priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+       } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
+               codec_dai_name = "ac97-hifi";
+               priv->card.set_bias_level = NULL;
+               priv->dai_fmt = SND_SOC_DAIFMT_AC97;
        } else {
                dev_err(&pdev->dev, "unknown Device Tree compatible\n");
                ret = -EINVAL;
                goto asrc_fail;
        }
 
+       if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
+               dev_err(&pdev->dev, "failed to find codec device\n");
+               ret = -EINVAL;
+               goto asrc_fail;
+       }
+
        /* Common settings for corresponding Freescale CPU DAI driver */
        if (strstr(cpu_np->name, "ssi")) {
                /* Only SSI needs to configure AUDMUX */
@@ -508,7 +565,9 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
        }
 
-       sprintf(priv->name, "%s-audio", codec_dev->name);
+       snprintf(priv->name, sizeof(priv->name), "%s-audio",
+                fsl_asoc_card_is_ac97(priv) ? "ac97" :
+                codec_dev->name);
 
        /* Initialize sound card */
        priv->pdev = pdev;
@@ -532,8 +591,26 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 
        /* Normal DAI Link */
        priv->dai_link[0].cpu_of_node = cpu_np;
-       priv->dai_link[0].codec_of_node = codec_np;
        priv->dai_link[0].codec_dai_name = codec_dai_name;
+
+       if (!fsl_asoc_card_is_ac97(priv))
+               priv->dai_link[0].codec_of_node = codec_np;
+       else {
+               u32 idx;
+
+               ret = of_property_read_u32(cpu_np, "cell-index", &idx);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "cannot get CPU index property\n");
+                       goto asrc_fail;
+               }
+
+               priv->dai_link[0].codec_name =
+                               devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                              "ac97-codec.%u",
+                                              (unsigned int)idx);
+       }
+
        priv->dai_link[0].platform_of_node = cpu_np;
        priv->dai_link[0].dai_fmt = priv->dai_fmt;
        priv->card.num_links = 1;
@@ -544,6 +621,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->dai_link[1].platform_of_node = asrc_np;
                priv->dai_link[2].codec_dai_name = codec_dai_name;
                priv->dai_link[2].codec_of_node = codec_np;
+               priv->dai_link[2].codec_name =
+                               priv->dai_link[0].codec_name;
                priv->dai_link[2].cpu_of_node = cpu_np;
                priv->dai_link[2].dai_fmt = priv->dai_fmt;
                priv->card.num_links = 3;
@@ -579,20 +658,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 
 asrc_fail:
        of_node_put(asrc_np);
-fail:
        of_node_put(codec_np);
+fail:
        of_node_put(cpu_np);
 
        return ret;
 }
 
 static const struct of_device_id fsl_asoc_card_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-ac97", },
        { .compatible = "fsl,imx-audio-cs42888", },
        { .compatible = "fsl,imx-audio-sgtl5000", },
        { .compatible = "fsl,imx-audio-wm8962", },
        { .compatible = "fsl,imx-audio-wm8960", },
        {}
 };
+MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
 
 static struct platform_driver fsl_asoc_card_driver = {
        .probe = fsl_asoc_card_probe,
index 837979ea5c922e58cfcf1044c9217cfdc2d01745..59f234e51971e2abfe7597dc7ad783a5972fbc76 100644 (file)
@@ -652,6 +652,24 @@ static const struct snd_soc_component_driver fsl_esai_component = {
        .name           = "fsl-esai",
 };
 
+static const struct reg_default fsl_esai_reg_defaults[] = {
+       {0x8,  0x00000000},
+       {0x10, 0x00000000},
+       {0x18, 0x00000000},
+       {0x98, 0x00000000},
+       {0xd0, 0x00000000},
+       {0xd4, 0x00000000},
+       {0xd8, 0x00000000},
+       {0xdc, 0x00000000},
+       {0xe0, 0x00000000},
+       {0xe4, 0x0000ffff},
+       {0xe8, 0x0000ffff},
+       {0xec, 0x0000ffff},
+       {0xf0, 0x0000ffff},
+       {0xf8, 0x00000000},
+       {0xfc, 0x00000000},
+};
+
 static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -684,6 +702,31 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
        }
 }
 
+static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_ESAI_ETDR:
+       case REG_ESAI_ERDR:
+       case REG_ESAI_ESR:
+       case REG_ESAI_TFSR:
+       case REG_ESAI_RFSR:
+       case REG_ESAI_TX0:
+       case REG_ESAI_TX1:
+       case REG_ESAI_TX2:
+       case REG_ESAI_TX3:
+       case REG_ESAI_TX4:
+       case REG_ESAI_TX5:
+       case REG_ESAI_RX0:
+       case REG_ESAI_RX1:
+       case REG_ESAI_RX2:
+       case REG_ESAI_RX3:
+       case REG_ESAI_SAISR:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -721,8 +764,12 @@ static const struct regmap_config fsl_esai_regmap_config = {
        .val_bits = 32,
 
        .max_register = REG_ESAI_PCRC,
+       .reg_defaults = fsl_esai_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_esai_reg_defaults),
        .readable_reg = fsl_esai_readable_reg,
+       .volatile_reg = fsl_esai_volatile_reg,
        .writeable_reg = fsl_esai_writeable_reg,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 static int fsl_esai_probe(struct platform_device *pdev)
@@ -853,10 +900,51 @@ static const struct of_device_id fsl_esai_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
 
+#ifdef CONFIG_PM_SLEEP
+static int fsl_esai_suspend(struct device *dev)
+{
+       struct fsl_esai *esai = dev_get_drvdata(dev);
+
+       regcache_cache_only(esai->regmap, true);
+       regcache_mark_dirty(esai->regmap);
+
+       return 0;
+}
+
+static int fsl_esai_resume(struct device *dev)
+{
+       struct fsl_esai *esai = dev_get_drvdata(dev);
+       int ret;
+
+       regcache_cache_only(esai->regmap, false);
+
+       /* FIFO reset for safety */
+       regmap_update_bits(esai->regmap, REG_ESAI_TFCR,
+                          ESAI_xFCR_xFR, ESAI_xFCR_xFR);
+       regmap_update_bits(esai->regmap, REG_ESAI_RFCR,
+                          ESAI_xFCR_xFR, ESAI_xFCR_xFR);
+
+       ret = regcache_sync(esai->regmap);
+       if (ret)
+               return ret;
+
+       /* FIFO reset done */
+       regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
+       regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_esai_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume)
+};
+
 static struct platform_driver fsl_esai_driver = {
        .probe = fsl_esai_probe,
        .driver = {
                .name = "fsl-esai-dai",
+               .pm = &fsl_esai_pm_ops,
                .of_match_table = fsl_esai_dt_ids,
        },
 };
index a18fd92c4a85c3d67306c544c1af6652789d1467..a4435f5e3be910447f9168b4708d19140f3c1f4f 100644 (file)
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
                       FSL_SAI_CSR_FEIE)
 
-static u32 fsl_sai_rates[] = {
+static const unsigned int fsl_sai_rates[] = {
        8000, 11025, 12000, 16000, 22050,
        24000, 32000, 44100, 48000, 64000,
        88200, 96000, 176400, 192000
 };
 
-static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
+static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
        .count = ARRAY_SIZE(fsl_sai_rates),
        .list = fsl_sai_rates,
 };
@@ -637,6 +637,8 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
 static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case FSL_SAI_TCSR:
+       case FSL_SAI_RCSR:
        case FSL_SAI_TFR:
        case FSL_SAI_RFR:
        case FSL_SAI_TDR:
@@ -681,6 +683,7 @@ static const struct regmap_config fsl_sai_regmap_config = {
        .readable_reg = fsl_sai_readable_reg,
        .volatile_reg = fsl_sai_volatile_reg,
        .writeable_reg = fsl_sai_writeable_reg,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int fsl_sai_probe(struct platform_device *pdev)
@@ -801,11 +804,42 @@ static const struct of_device_id fsl_sai_ids[] = {
        { .compatible = "fsl,imx6sx-sai", },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_sai_suspend(struct device *dev)
+{
+       struct fsl_sai *sai = dev_get_drvdata(dev);
+
+       regcache_cache_only(sai->regmap, true);
+       regcache_mark_dirty(sai->regmap);
+
+       return 0;
+}
+
+static int fsl_sai_resume(struct device *dev)
+{
+       struct fsl_sai *sai = dev_get_drvdata(dev);
+
+       regcache_cache_only(sai->regmap, false);
+       regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+       msleep(1);
+       regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+       return regcache_sync(sai->regmap);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_sai_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fsl_sai_suspend, fsl_sai_resume)
+};
 
 static struct platform_driver fsl_sai_driver = {
        .probe = fsl_sai_probe,
        .driver = {
                .name = "fsl-sai",
+               .pm = &fsl_sai_pm_ops,
                .of_match_table = fsl_sai_ids,
        },
 };
index ab729f2426fe3ce18ca19b3adedf0e3fe946b3b3..3d59bb6719f2b6fea0d7ed7137940bac88d99d6b 100644 (file)
@@ -108,6 +108,8 @@ struct fsl_spdif_priv {
        struct clk *sysclk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
+       /* regcache for SRPC */
+       u32 regcache_srpc;
 };
 
 /* DPLL locked and lock loss interrupt handler */
@@ -300,6 +302,8 @@ static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
        struct regmap *regmap = spdif_priv->regmap;
        u32 val, cycle = 1000;
 
+       regcache_cache_bypass(regmap, true);
+
        regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
 
        /*
@@ -310,6 +314,10 @@ static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
                regmap_read(regmap, REG_SPDIF_SCR, &val);
        } while ((val & SCR_SOFT_RESET) && cycle--);
 
+       regcache_cache_bypass(regmap, false);
+       regcache_mark_dirty(regmap);
+       regcache_sync(regmap);
+
        if (cycle)
                return 0;
        else
@@ -997,6 +1005,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
 };
 
 /* FSL SPDIF REGMAP */
+static const struct reg_default fsl_spdif_reg_defaults[] = {
+       {0x0,  0x00000400},
+       {0x4,  0x00000000},
+       {0xc,  0x00000000},
+       {0x34, 0x00000000},
+       {0x38, 0x00000000},
+       {0x50, 0x00020f00},
+};
 
 static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
 {
@@ -1022,6 +1038,26 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
        }
 }
 
+static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_SPDIF_SRPC:
+       case REG_SPDIF_SIS:
+       case REG_SPDIF_SRL:
+       case REG_SPDIF_SRR:
+       case REG_SPDIF_SRCSH:
+       case REG_SPDIF_SRCSL:
+       case REG_SPDIF_SRU:
+       case REG_SPDIF_SRQ:
+       case REG_SPDIF_STL:
+       case REG_SPDIF_STR:
+       case REG_SPDIF_SRFM:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -1047,8 +1083,12 @@ static const struct regmap_config fsl_spdif_regmap_config = {
        .val_bits = 32,
 
        .max_register = REG_SPDIF_STC,
+       .reg_defaults = fsl_spdif_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_spdif_reg_defaults),
        .readable_reg = fsl_spdif_readable_reg,
+       .volatile_reg = fsl_spdif_volatile_reg,
        .writeable_reg = fsl_spdif_writeable_reg,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
@@ -1271,6 +1311,38 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        return ret;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int fsl_spdif_suspend(struct device *dev)
+{
+       struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+
+       regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
+                       &spdif_priv->regcache_srpc);
+
+       regcache_cache_only(spdif_priv->regmap, true);
+       regcache_mark_dirty(spdif_priv->regmap);
+
+       return 0;
+}
+
+static int fsl_spdif_resume(struct device *dev)
+{
+       struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+
+       regcache_cache_only(spdif_priv->regmap, false);
+
+       regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC,
+                       SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+                       spdif_priv->regcache_srpc);
+
+       return regcache_sync(spdif_priv->regmap);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_spdif_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume)
+};
+
 static const struct of_device_id fsl_spdif_dt_ids[] = {
        { .compatible = "fsl,imx35-spdif", },
        { .compatible = "fsl,vf610-spdif", },
@@ -1282,6 +1354,7 @@ static struct platform_driver fsl_spdif_driver = {
        .driver = {
                .name = "fsl-spdif-dai",
                .of_match_table = fsl_spdif_dt_ids,
+               .pm = &fsl_spdif_pm,
        },
        .probe = fsl_spdif_probe,
 };
index 37c5cd4d0e59038ca72c8520bb350de60e42a278..95d2392303eb449bdcf5375872c9edd21aae36c7 100644 (file)
@@ -111,12 +111,75 @@ struct fsl_ssi_rxtx_reg_val {
        struct fsl_ssi_reg_val rx;
        struct fsl_ssi_reg_val tx;
 };
+
+static const struct reg_default fsl_ssi_reg_defaults[] = {
+       {0x10, 0x00000000},
+       {0x18, 0x00003003},
+       {0x1c, 0x00000200},
+       {0x20, 0x00000200},
+       {0x24, 0x00040000},
+       {0x28, 0x00040000},
+       {0x38, 0x00000000},
+       {0x48, 0x00000000},
+       {0x4c, 0x00000000},
+       {0x54, 0x00000000},
+       {0x58, 0x00000000},
+};
+
+static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CCSR_SSI_SACCEN:
+       case CCSR_SSI_SACCDIS:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CCSR_SSI_STX0:
+       case CCSR_SSI_STX1:
+       case CCSR_SSI_SRX0:
+       case CCSR_SSI_SRX1:
+       case CCSR_SSI_SISR:
+       case CCSR_SSI_SFCSR:
+       case CCSR_SSI_SACADD:
+       case CCSR_SSI_SACDAT:
+       case CCSR_SSI_SATAG:
+       case CCSR_SSI_SACCST:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CCSR_SSI_SRX0:
+       case CCSR_SSI_SRX1:
+       case CCSR_SSI_SACCST:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static const struct regmap_config fsl_ssi_regconfig = {
        .max_register = CCSR_SSI_SACCDIS,
        .reg_bits = 32,
        .val_bits = 32,
        .reg_stride = 4,
        .val_format_endian = REGMAP_ENDIAN_NATIVE,
+       .reg_defaults = fsl_ssi_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
+       .readable_reg = fsl_ssi_readable_reg,
+       .volatile_reg = fsl_ssi_volatile_reg,
+       .writeable_reg = fsl_ssi_writeable_reg,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 struct fsl_ssi_soc_data {
@@ -176,6 +239,9 @@ struct fsl_ssi_private {
        unsigned int baudclk_streams;
        unsigned int bitclk_freq;
 
+       /*regcache for SFCSR*/
+       u32 regcache_sfcsr;
+
        /* DMA params */
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -1514,10 +1580,46 @@ static int fsl_ssi_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int fsl_ssi_suspend(struct device *dev)
+{
+       struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
+       struct regmap *regs = ssi_private->regs;
+
+       regmap_read(regs, CCSR_SSI_SFCSR,
+                       &ssi_private->regcache_sfcsr);
+
+       regcache_cache_only(regs, true);
+       regcache_mark_dirty(regs);
+
+       return 0;
+}
+
+static int fsl_ssi_resume(struct device *dev)
+{
+       struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
+       struct regmap *regs = ssi_private->regs;
+
+       regcache_cache_only(regs, false);
+
+       regmap_update_bits(regs, CCSR_SSI_SFCSR,
+                       CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
+                       CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
+                       ssi_private->regcache_sfcsr);
+
+       return regcache_sync(regs);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_ssi_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
+};
+
 static struct platform_driver fsl_ssi_driver = {
        .driver = {
                .name = "fsl-ssi-dai",
                .of_match_table = fsl_ssi_ids,
+               .pm = &fsl_ssi_pm,
        },
        .probe = fsl_ssi_probe,
        .remove = fsl_ssi_remove,
index 33da26a1245718f4b6e814bb22e04218ecc340fc..a407e833c612523e90c07a732e9cc472b64252ee 100644 (file)
@@ -89,6 +89,7 @@ MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
 static struct platform_driver imx_spdif_driver = {
        .driver = {
                .name = "imx-spdif",
+               .pm = &snd_soc_pm_ops,
                .of_match_table = imx_spdif_dt_ids,
        },
        .probe = imx_spdif_audio_probe,
index 3ff76d419436ebbac7ac194e42510495a715f183..54c33204541fdb23dc78c8e2e801f3075fc1fd11 100644 (file)
@@ -151,7 +151,9 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
        }
 
        if (set->slots) {
-               ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
+               ret = snd_soc_dai_set_tdm_slot(dai,
+                                              set->tx_slot_mask,
+                                              set->rx_slot_mask,
                                                set->slots,
                                                set->slot_width);
                if (ret && ret != -ENOTSUPP) {
@@ -243,7 +245,9 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                return ret;
 
        /* Parse TDM slot */
-       ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
+       ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask,
+                                       &dai->rx_slot_mask,
+                                       &dai->slots, &dai->slot_width);
        if (ret)
                return ret;
 
index 05fde5e6e2578396aa4e4be20d84d3b35d3bc6ff..7b778ab85f8b41234487d0810f4c350f6dc09775 100644 (file)
@@ -12,6 +12,7 @@ config SND_MFLD_MACHINE
 
 config SND_SST_MFLD_PLATFORM
        tristate
+       select SND_SOC_COMPRESS
 
 config SND_SST_IPC
        tristate
@@ -138,4 +139,18 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
 config SND_SOC_INTEL_SKYLAKE
        tristate
        select SND_HDA_EXT_CORE
+       select SND_SOC_TOPOLOGY
        select SND_SOC_INTEL_SST
+
+config SND_SOC_INTEL_SKL_RT286_MACH
+       tristate "ASoC Audio driver for SKL with RT286 I2S mode"
+       depends on X86 && ACPI
+       select SND_SOC_INTEL_SST
+       select SND_SOC_INTEL_SKYLAKE
+       select SND_SOC_RT286
+       select SND_SOC_DMIC
+       help
+          This adds support for ASoC machine driver for Skylake platforms
+          with RT286 I2S audio codec.
+          Say Y if you have such a device
+          If unsure select "N".
index 683e5011615241b026d91c4056ce3cb28e97c537..0487cfaac5385a5c8201fbb80cf1b28040e18c74 100644 (file)
@@ -368,23 +368,6 @@ static void sst_media_close(struct snd_pcm_substream *substream,
        kfree(stream);
 }
 
-static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
-                                              struct snd_pcm_substream *substream)
-{
-       struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
-       struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       u32 str_id = stream->stream_info.str_id;
-       unsigned int pipe_id;
-
-       pipe_id = map[str_id].device_id;
-
-       dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
-                       pipe_id, str_id);
-       return pipe_id;
-}
-
 static int sst_media_prepare(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -529,7 +512,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 {
        .name = "compress-cpu-dai",
-       .compress_dai = 1,
+       .compress_new = snd_soc_new_compress,
        .ops = &sst_compr_dai_ops,
        .playback = {
                .stream_name = "Compress Playback",
index cb94895c9edb040e0e0bcdf33c9f80c1fb4215c9..371c4565cad8ae9be0574be0f4d60bd54d3d34bf 100644 (file)
@@ -6,6 +6,7 @@ snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
+snd-soc-skl_rt286-objs := skl_rt286.o
 
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -15,3 +16,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
index 8bafaf6ceab1266f6b85a0d6ca1e4ee04bc5046f..3f8a1e10bed02841f6b437d3d4a24615879ca35e 100644 (file)
@@ -266,18 +266,11 @@ static int broadwell_audio_probe(struct platform_device *pdev)
 {
        broadwell_rt286.dev = &pdev->dev;
 
-       return snd_soc_register_card(&broadwell_rt286);
-}
-
-static int broadwell_audio_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_card(&broadwell_rt286);
-       return 0;
+       return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
 }
 
 static struct platform_driver broadwell_audio = {
        .probe = broadwell_audio_probe,
-       .remove = broadwell_audio_remove,
        .driver = {
                .name = "broadwell-audio",
        },
index c4453120b11a33c60dc08422b49096f2700ce872..7a5c9a36c1db670081c70480e71e6d6b2a3ef538 100644 (file)
@@ -117,20 +117,10 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
 static int byt_aif1_startup(struct snd_pcm_substream *substream)
 {
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
 static struct snd_soc_ops byt_aif1_ops = {
index 49f4869cec48a273595f145cae120fa1485e88e6..4e2fcf188dd1e0be1dce9a618929235f35bcb5a0 100644 (file)
@@ -193,20 +193,10 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
 static int cht_aif1_startup(struct snd_pcm_substream *substream)
 {
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
 static int cht_max98090_headset_init(struct snd_soc_component *component)
index 7be8461e4d3bd45c32b921b96acc1817bcb3584f..38d65a3529c4fc1fda0464d05057e0055b6afe35 100644 (file)
@@ -235,20 +235,10 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
 static int cht_aif1_startup(struct snd_pcm_substream *substream)
 {
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
 static struct snd_soc_ops cht_aif1_ops = {
index 23fe0407514209d2ddfd67b7e076f099c5e73f5d..5621ccd92992d9f198bd5d0fd6149f06d0a3631a 100644 (file)
@@ -222,20 +222,10 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static unsigned int rates_48000[] = {
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_48000 = {
-       .count = ARRAY_SIZE(rates_48000),
-       .list  = rates_48000,
-};
-
 static int cht_aif1_startup(struct snd_pcm_substream *substream)
 {
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       &constraints_48000);
+       return snd_pcm_hw_constraint_single(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
 static struct snd_soc_ops cht_aif1_ops = {
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
new file mode 100644 (file)
index 0000000..a73a431
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Intel Skylake I2S Machine Driver
+ *
+ * Copyright (C) 2014-2015, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ *   Intel Broadwell Wildcatpoint SST Audio
+ *
+ *   Copyright (C) 2013, Intel Corporation. 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 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include "../../codecs/rt286.h"
+
+static struct snd_soc_jack skylake_headset;
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin skylake_headset_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("DMIC2", NULL),
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route skylake_rt286_map[] = {
+       /* speaker */
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+
+       /* HP jack connectors - unknown if we have jack deteck */
+       {"Headphone Jack", NULL, "HPO Pin"},
+
+       /* other jacks */
+       {"MIC1", NULL, "Mic Jack"},
+
+       /* digital mics */
+       {"DMIC1 Pin", NULL, "DMIC2"},
+       {"DMIC AIF", NULL, "SoC DMIC"},
+
+       /* CODEC BE connections */
+       { "AIF1 Playback", NULL, "ssp0 Tx"},
+       { "ssp0 Tx", NULL, "codec0_out"},
+       { "ssp0 Tx", NULL, "codec1_out"},
+
+       { "codec0_in", NULL, "ssp0 Rx" },
+       { "codec1_in", NULL, "ssp0 Rx" },
+       { "ssp0 Rx", NULL, "AIF1 Capture" },
+
+       { "dmic01_hifi", NULL, "DMIC01 Rx" },
+       { "DMIC01 Rx", NULL, "Capture" },
+
+       { "hif1", NULL, "iDisp Tx"},
+       { "iDisp Tx", NULL, "iDisp_out"},
+
+};
+
+static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "Headset",
+               SND_JACK_HEADSET | SND_JACK_BTN_0,
+               &skylake_headset,
+               skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins));
+
+       if (ret)
+               return ret;
+
+       rt286_mic_detect(codec, &skylake_headset);
+
+       return 0;
+}
+
+
+static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The output is 48KHz, stereo, 16bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+       return 0;
+}
+
+static int skylake_rt286_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
+
+       return ret;
+}
+
+static struct snd_soc_ops skylake_rt286_ops = {
+       .hw_params = skylake_rt286_hw_params,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_rt286_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "Skl Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST,
+                       SND_SOC_DPCM_TRIGGER_POST
+               },
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Skl Audio Capture Port",
+               .stream_name = "Audio Record",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "0000:00:1f.3",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {
+                       SND_SOC_DPCM_TRIGGER_POST,
+                       SND_SOC_DPCM_TRIGGER_POST
+               },
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "Skl Audio Reference cap",
+               .stream_name = "refcap",
+               .cpu_dai_name = "Reference Pin",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "0000:00:1f.3",
+               .init = NULL,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .nonatomic = 1,
+               .dynamic = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "SSP0-Codec",
+               .be_id = 0,
+               .cpu_dai_name = "SSP0 Pin",
+               .platform_name = "0000:00:1f.3",
+               .no_pcm = 1,
+               .codec_name = "i2c-INT343A:00",
+               .codec_dai_name = "rt286-aif1",
+               .init = skylake_rt286_codec_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = skylake_ssp0_fixup,
+               .ops = &skylake_rt286_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "dmic01",
+               .be_id = 1,
+               .cpu_dai_name = "DMIC01 Pin",
+               .codec_name = "dmic-codec",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "0000:00:1f.3",
+               .ignore_suspend = 1,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+};
+
+/* skylake audio machine driver for SPT + RT286S */
+static struct snd_soc_card skylake_rt286 = {
+       .name = "skylake-rt286",
+       .owner = THIS_MODULE,
+       .dai_link = skylake_rt286_dais,
+       .num_links = ARRAY_SIZE(skylake_rt286_dais),
+       .controls = skylake_controls,
+       .num_controls = ARRAY_SIZE(skylake_controls),
+       .dapm_widgets = skylake_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+       .dapm_routes = skylake_rt286_map,
+       .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
+       .fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+       skylake_rt286.dev = &pdev->dev;
+
+       return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
+}
+
+static struct platform_driver skylake_audio = {
+       .probe = skylake_audio_probe,
+       .driver = {
+               .name = "skl_alc286s_i2s",
+       },
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>");
+MODULE_DESCRIPTION("Intel SST Audio for Skylake");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_alc286s_i2s");
index f24154ca4e983e615a40f6abc3f6734ecce5039a..d9105584c51f5838a4ebbc360eb35ce91c56b1be 100644 (file)
@@ -1,7 +1,11 @@
-snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
+snd-soc-sst-dsp-objs := sst-dsp.o
 snd-soc-sst-acpi-objs := sst-acpi.o
 snd-soc-sst-ipc-objs := sst-ipc.o
 
+ifneq ($(CONFIG_DW_DMAC_CORE),)
+snd-soc-sst-dsp-objs += sst-firmware.o
+endif
+
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
 obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
 
index cbd568eac033ebe3aa1af77a2b51ec92e3ccae50..2151652d37b72e33c556b11ea46af565747fd965 100644 (file)
@@ -314,6 +314,7 @@ struct sst_dsp {
        int sst_state;
        struct skl_cl_dev cl_dev;
        u32 intr_status;
+       const struct firmware *fw;
 };
 
 /* Size optimised DRAM/IRAM memcpy */
index a627236dd1f5b47e47e132c6feae996bdfcb9dc1..c9452e02e0dda6735238736a9e8d05267615abb0 100644 (file)
@@ -420,6 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
 }
 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
 
+#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
 struct sst_dsp *sst_dsp_new(struct device *dev,
        struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
 {
@@ -484,6 +485,7 @@ void sst_dsp_free(struct sst_dsp *sst)
        sst_dma_free(sst->dma);
 }
 EXPORT_SYMBOL_GPL(sst_dsp_free);
+#endif
 
 /* Module information */
 MODULE_AUTHOR("Liam Girdwood");
index 1f45f18715c09ef44ccb0b31930f27ae875673b6..859f0de003391489b2da65c0195f62caa2e0b9ef 100644 (file)
@@ -216,10 +216,12 @@ struct sst_pdata {
        void *dsp;
 };
 
+#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
 /* Initialization */
 struct sst_dsp *sst_dsp_new(struct device *dev,
        struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
 void sst_dsp_free(struct sst_dsp *sst);
+#endif
 
 /* SHIM Read / Write */
 void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
index ebcca6dc48d189eb16b8903683db5460a3955357..1636a1eeb0021efa076674e3375db682c1cbb45b 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/acpi.h>
 
 /* supported DMA engine drivers */
-#include <linux/platform_data/dma-dw.h>
 #include <linux/dma/dw.h>
 
 #include <asm/page.h>
@@ -169,12 +168,6 @@ err:
        return ret;
 }
 
-static struct dw_dma_platform_data dw_pdata = {
-       .is_private = 1,
-       .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
-       .chan_priority = CHAN_PRIORITY_ASCENDING,
-};
-
 static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
        int irq)
 {
@@ -195,7 +188,8 @@ static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
                return ERR_PTR(err);
 
        chip->dev = dev;
-       err = dw_dma_probe(chip, &dw_pdata);
+
+       err = dw_dma_probe(chip, NULL);
        if (err)
                return ERR_PTR(err);
 
index 27db22178204b1bdb5d65502d1b905f7714fd1df..914b6dab9beae20fa0421f06d9c21f0f58d3dd64 100644 (file)
@@ -1,4 +1,5 @@
-snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o
+snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \
+skl-topology.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
 
index 826d4fd8930a5ca802f07bef5542bc26c199ffdf..50a109503a3fefbe41b1c153b8c96f975a4a6d1f 100644 (file)
@@ -54,6 +54,24 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
        return 0;
 }
 
+#define NOTIFICATION_PARAM_ID 3
+#define NOTIFICATION_MASK 0xf
+
+/* disable notfication for underruns/overruns from firmware module */
+static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
+{
+       struct notification_mask mask;
+       struct skl_ipc_large_config_msg msg = {0};
+
+       mask.notify = NOTIFICATION_MASK;
+       mask.enable = enable;
+
+       msg.large_param_id = NOTIFICATION_PARAM_ID;
+       msg.param_data_size = sizeof(mask);
+
+       skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask);
+}
+
 int skl_init_dsp(struct skl *skl)
 {
        void __iomem *mmio_base;
@@ -79,7 +97,10 @@ int skl_init_dsp(struct skl *skl)
 
        ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
                        loader_ops, &skl->skl_sst);
+       if (ret < 0)
+               return ret;
 
+       skl_dsp_enable_notification(skl->skl_sst, false);
        dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
 
        return ret;
@@ -122,6 +143,7 @@ int skl_suspend_dsp(struct skl *skl)
 int skl_resume_dsp(struct skl *skl)
 {
        struct skl_sst *ctx = skl->skl_sst;
+       int ret;
 
        /* if ppcap is not supported return 0 */
        if (!skl->ebus.ppcap)
@@ -131,7 +153,12 @@ int skl_resume_dsp(struct skl *skl)
        snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
        snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
 
-       return skl_dsp_wake(ctx->dsp);
+       ret = skl_dsp_wake(ctx->dsp);
+       if (ret < 0)
+               return ret;
+
+       skl_dsp_enable_notification(skl->skl_sst, false);
+       return ret;
 }
 
 enum skl_bitdepth skl_get_bit_depth(int params)
@@ -294,6 +321,7 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
                        (mconfig->formats_config.caps_size) / 4;
 }
 
+#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF
 /*
  * Calculate the gatewat settings required for copier module, type of
  * gateway and index of gateway to use
@@ -303,6 +331,7 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                        struct skl_cpr_cfg *cpr_mconfig)
 {
        union skl_connector_node_id node_id = {0};
+       union skl_ssp_dma_node ssp_node  = {0};
        struct skl_pipe_params *params = mconfig->pipe->p_params;
 
        switch (mconfig->dev_type) {
@@ -320,9 +349,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                        (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
                        SKL_DMA_I2S_LINK_OUTPUT_CLASS :
                        SKL_DMA_I2S_LINK_INPUT_CLASS;
-               node_id.node.vindex = params->host_dma_id +
-                                        (mconfig->time_slot << 1) +
-                                        (mconfig->vbus_id << 3);
+               ssp_node.dma_node.time_slot_index = mconfig->time_slot;
+               ssp_node.dma_node.i2s_instance = mconfig->vbus_id;
+               node_id.node.vindex = ssp_node.val;
                break;
 
        case SKL_DEVICE_DMIC:
@@ -339,13 +368,18 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
                node_id.node.vindex = params->link_dma_id;
                break;
 
-       default:
+       case SKL_DEVICE_HDAHOST:
                node_id.node.dma_type =
                        (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
                        SKL_DMA_HDA_HOST_OUTPUT_CLASS :
                        SKL_DMA_HDA_HOST_INPUT_CLASS;
                node_id.node.vindex = params->host_dma_id;
                break;
+
+       default:
+               cpr_mconfig->gtw_cfg.node_id = SKL_NON_GATEWAY_CPR_NODE_ID;
+               cpr_mconfig->cpr_feature_mask = 0;
+               return;
        }
 
        cpr_mconfig->gtw_cfg.node_id = node_id.val;
index 13036b19d7e55f81aa77d511be5fc5f8ca87ebdf..b0c7bd113aacfd59db229320f5227985010bb8f4 100644 (file)
@@ -25,7 +25,7 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
 
 #define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
 
-void __iomem *skl_nhlt_init(struct device *dev)
+void *skl_nhlt_init(struct device *dev)
 {
        acpi_handle handle;
        union acpi_object *obj;
@@ -40,17 +40,17 @@ void __iomem *skl_nhlt_init(struct device *dev)
        if (obj && obj->type == ACPI_TYPE_BUFFER) {
                nhlt_ptr = (struct nhlt_resource_desc  *)obj->buffer.pointer;
 
-               return ioremap_cache(nhlt_ptr->min_addr, nhlt_ptr->length);
+               return memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
+                               MEMREMAP_WB);
        }
 
        dev_err(dev, "device specific method to extract NHLT blob failed\n");
        return NULL;
 }
 
-void skl_nhlt_free(void __iomem *addr)
+void skl_nhlt_free(void *addr)
 {
-       iounmap(addr);
-       addr = NULL;
+       memunmap(addr);
 }
 
 static struct nhlt_specific_cfg *skl_get_specific_cfg(
index 7d617bf493bc7a1295560d034d76ba161e2eb431..a2f94ce1679d0db2c23b3ccb0d0339afb46473cf 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include "skl.h"
+#include "skl-topology.h"
 
 #define HDA_MONO 1
 #define HDA_STEREO 2
@@ -115,7 +116,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
        ret = pm_runtime_get_sync(dai->dev);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        stream = snd_hdac_ext_stream_assign(ebus, substream,
@@ -214,6 +215,8 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
        struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct skl_pipe_params p_params = {0};
+       struct skl_module_cfg *m_cfg;
        int ret, dma_id;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
@@ -228,6 +231,16 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
        dma_id = hdac_stream(stream)->stream_tag - 1;
        dev_dbg(dai->dev, "dma_id=%d\n", dma_id);
 
+       p_params.s_fmt = snd_pcm_format_width(params_format(params));
+       p_params.ch = params_channels(params);
+       p_params.s_freq = params_rate(params);
+       p_params.host_dma_id = dma_id;
+       p_params.stream = substream->stream;
+
+       m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
+       if (m_cfg)
+               skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params);
+
        return 0;
 }
 
@@ -268,6 +281,46 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
        return skl_substream_free_pages(ebus_to_hbus(ebus), substream);
 }
 
+static int skl_be_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct skl_pipe_params p_params = {0};
+
+       p_params.s_fmt = snd_pcm_format_width(params_format(params));
+       p_params.ch = params_channels(params);
+       p_params.s_freq = params_rate(params);
+       p_params.stream = substream->stream;
+       skl_tplg_be_update_params(dai, &p_params);
+
+       return 0;
+}
+
+static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+               struct snd_soc_dai *dai)
+{
+       struct skl *skl = get_skl_ctx(dai->dev);
+       struct skl_sst *ctx = skl->skl_sst;
+       struct skl_module_cfg *mconfig;
+
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       if (!mconfig)
+               return -EIO;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               return skl_run_pipe(ctx, mconfig->pipe);
+
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               return skl_stop_pipe(ctx, mconfig->pipe);
+
+       default:
+               return 0;
+       }
+}
+
 static int skl_link_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -277,9 +330,8 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct skl_dma_params *dma_params;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int dma_id;
+       struct skl_pipe_params p_params = {0};
 
-       pr_debug("%s\n", __func__);
        link_dev = snd_hdac_ext_stream_assign(ebus, substream,
                                        HDAC_EXT_STREAM_TYPE_LINK);
        if (!link_dev)
@@ -293,7 +345,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
        if (dma_params)
                dma_params->stream_tag =  hdac_stream(link_dev)->stream_tag;
        snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params);
-       dma_id = hdac_stream(link_dev)->stream_tag - 1;
+
+       p_params.s_fmt = snd_pcm_format_width(params_format(params));
+       p_params.ch = params_channels(params);
+       p_params.s_freq = params_rate(params);
+       p_params.stream = substream->stream;
+       p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
+
+       skl_tplg_be_update_params(dai, &p_params);
 
        return 0;
 }
@@ -308,27 +367,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
        unsigned int format_val = 0;
        struct skl_dma_params *dma_params;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_pcm_hw_params *params;
-       struct snd_interval *channels, *rate;
        struct hdac_ext_link *link;
 
-       dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
        if (link_dev->link_prepared) {
                dev_dbg(dai->dev, "already stream is prepared - returning\n");
                return 0;
        }
-       params  = devm_kzalloc(dai->dev, sizeof(*params), GFP_KERNEL);
-       if (params == NULL)
-               return -ENOMEM;
-
-       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-       channels->min = channels->max = substream->runtime->channels;
-       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       rate->min = rate->max = substream->runtime->rate;
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                       SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                       substream->runtime->format);
-
 
        dma_params  = (struct skl_dma_params *)
                        snd_soc_dai_get_dma_data(codec_dai, substream);
@@ -399,13 +443,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int skl_hda_be_startup(struct snd_pcm_substream *substream,
+static int skl_be_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        return pm_runtime_get_sync(dai->dev);
 }
 
-static void skl_hda_be_shutdown(struct snd_pcm_substream *substream,
+static void skl_be_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        pm_runtime_mark_last_busy(dai->dev);
@@ -418,20 +462,28 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
        .prepare = skl_pcm_prepare,
        .hw_params = skl_pcm_hw_params,
        .hw_free = skl_pcm_hw_free,
+       .trigger = skl_pcm_trigger,
 };
 
 static struct snd_soc_dai_ops skl_dmic_dai_ops = {
-       .startup = skl_hda_be_startup,
-       .shutdown = skl_hda_be_shutdown,
+       .startup = skl_be_startup,
+       .hw_params = skl_be_hw_params,
+       .shutdown = skl_be_shutdown,
+};
+
+static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
+       .startup = skl_be_startup,
+       .hw_params = skl_be_hw_params,
+       .shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_ops skl_link_dai_ops = {
-       .startup = skl_hda_be_startup,
+       .startup = skl_be_startup,
        .prepare = skl_link_pcm_prepare,
        .hw_params = skl_link_hw_params,
        .hw_free = skl_link_hw_free,
        .trigger = skl_link_pcm_trigger,
-       .shutdown = skl_hda_be_shutdown,
+       .shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_driver skl_platform_dai[] = {
@@ -487,6 +539,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
        },
 },
 /* BE CPU  Dais */
+{
+       .name = "SSP0 Pin",
+       .ops = &skl_be_ssp_dai_ops,
+       .playback = {
+               .stream_name = "ssp0 Tx",
+               .channels_min = HDA_STEREO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "ssp0 Rx",
+               .channels_min = HDA_STEREO,
+               .channels_max = HDA_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
 {
        .name = "iDisp Pin",
        .ops = &skl_link_dai_ops,
@@ -509,17 +579,6 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
        },
 },
-{
-       .name = "DMIC23 Pin",
-       .ops = &skl_dmic_dai_ops,
-       .capture = {
-               .stream_name = "DMIC23 Rx",
-               .channels_min = HDA_STEREO,
-               .channels_max = HDA_STEREO,
-               .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
-       },
-},
 {
        .name = "HD-Codec Pin",
        .ops = &skl_link_dai_ops,
@@ -538,28 +597,6 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 },
-{
-       .name = "HD-Codec-SPK Pin",
-       .ops = &skl_link_dai_ops,
-       .playback = {
-               .stream_name = "HD-Codec-SPK Tx",
-               .channels_min = HDA_STEREO,
-               .channels_max = HDA_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-{
-       .name = "HD-Codec-AMIC Pin",
-       .ops = &skl_link_dai_ops,
-       .capture = {
-               .stream_name = "HD-Codec-AMIC Rx",
-               .channels_min = HDA_STEREO,
-               .channels_max = HDA_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
 };
 
 static int skl_platform_open(struct snd_pcm_substream *substream)
@@ -577,7 +614,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int skl_pcm_trigger(struct snd_pcm_substream *substream,
+static int skl_coupled_trigger(struct snd_pcm_substream *substream,
                                        int cmd)
 {
        struct hdac_ext_bus *ebus = get_bus_ctx(substream);
@@ -651,7 +688,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int skl_dsp_trigger(struct snd_pcm_substream *substream,
+static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
                int cmd)
 {
        struct hdac_ext_bus *ebus = get_bus_ctx(substream);
@@ -708,9 +745,9 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
        struct hdac_ext_bus *ebus = get_bus_ctx(substream);
 
        if (ebus->ppcap)
-               return skl_dsp_trigger(substream, cmd);
+               return skl_decoupled_trigger(substream, cmd);
        else
-               return skl_pcm_trigger(substream, cmd);
+               return skl_coupled_trigger(substream, cmd);
 }
 
 /* calculate runtime delay from LPIB */
@@ -877,7 +914,17 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
        return retval;
 }
 
+static int skl_platform_soc_probe(struct snd_soc_platform *platform)
+{
+       struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev);
+
+       if (ebus->ppcap)
+               return skl_tplg_init(platform, ebus);
+
+       return 0;
+}
 static struct snd_soc_platform_driver skl_platform_drv  = {
+       .probe          = skl_platform_soc_probe,
        .ops            = &skl_platform_ops,
        .pcm_new        = skl_pcm_new,
        .pcm_free       = skl_pcm_free,
@@ -890,6 +937,11 @@ static const struct snd_soc_component_driver skl_component = {
 int skl_platform_register(struct device *dev)
 {
        int ret;
+       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+       struct skl *skl = ebus_to_skl(ebus);
+
+       INIT_LIST_HEAD(&skl->ppl_list);
+       INIT_LIST_HEAD(&skl->dapm_path_list);
 
        ret = snd_soc_register_platform(dev, &skl_platform_drv);
        if (ret) {
index 94875b008b0b83a221789f281852d195305faf9c..1bfb7f63b5724d98e8acf1446364fafec01e115f 100644 (file)
@@ -175,7 +175,7 @@ static int skl_dsp_core_power_down(struct sst_dsp  *ctx)
        /* poll with timeout to check if operation successful */
        return sst_dsp_register_poll(ctx,
                        SKL_ADSP_REG_ADSPCS,
-                       SKL_ADSPCS_SPA_MASK,
+                       SKL_ADSPCS_CPA_MASK,
                        0,
                        SKL_DSP_PD_TO,
                        "Power down");
@@ -262,6 +262,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
        val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
        ctx->intr_status = val;
 
+       if (val == 0xffffffff) {
+               spin_unlock(&ctx->spinlock);
+               return IRQ_NONE;
+       }
+
        if (val & SKL_ADSPIS_IPC) {
                skl_ipc_int_disable(ctx);
                result = IRQ_WAKE_THREAD;
index 937a0a3a63a0f0241cb19c89f79a2410665d898a..3345ea0d44147e9fdb62275f73d1d0d6d64e0c5f 100644 (file)
@@ -464,6 +464,18 @@ void skl_ipc_op_int_enable(struct sst_dsp *ctx)
                SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY);
 }
 
+void skl_ipc_op_int_disable(struct sst_dsp *ctx)
+{
+       /* disable IPC DONE interrupt */
+       sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
+                                       SKL_ADSP_REG_HIPCCTL_DONE, 0);
+
+       /* Disable IPC BUSY interrupt */
+       sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
+                                       SKL_ADSP_REG_HIPCCTL_BUSY, 0);
+
+}
+
 bool skl_ipc_int_status(struct sst_dsp *ctx)
 {
        return sst_dsp_shim_read_unlocked(ctx,
index 9f5f67202858fdbbcfe665c9a9275bfae1f073e7..f1a154e45dc343209b7a1adb8010f62313785bf8 100644 (file)
@@ -116,6 +116,7 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
 
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
+void skl_ipc_op_int_disable(struct sst_dsp *ctx);
 void skl_ipc_int_disable(struct sst_dsp *dsp);
 
 bool skl_ipc_int_status(struct sst_dsp *dsp);
index c18ea51b7484d13e0ed79d3d56f774d6c55b653f..3b83dc99f1d405ffd5ea65e1376cae6920a99e63 100644 (file)
@@ -70,15 +70,31 @@ static int skl_transfer_firmware(struct sst_dsp *ctx,
 static int skl_load_base_firmware(struct sst_dsp *ctx)
 {
        int ret = 0, i;
-       const struct firmware *fw = NULL;
        struct skl_sst *skl = ctx->thread_context;
        u32 reg;
 
-       ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev);
+       skl->boot_complete = false;
+       init_waitqueue_head(&skl->boot_wait);
+
+       if (ctx->fw == NULL) {
+               ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev);
+               if (ret < 0) {
+                       dev_err(ctx->dev, "Request firmware failed %d\n", ret);
+                       skl_dsp_disable_core(ctx);
+                       return -EIO;
+               }
+       }
+
+       ret = skl_dsp_boot(ctx);
        if (ret < 0) {
-               dev_err(ctx->dev, "Request firmware failed %d\n", ret);
-               skl_dsp_disable_core(ctx);
-               return -EIO;
+               dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret);
+               goto skl_load_base_firmware_failed;
+       }
+
+       ret = skl_cldma_prepare(ctx);
+       if (ret < 0) {
+               dev_err(ctx->dev, "CL dma prepare failed : %d", ret);
+               goto skl_load_base_firmware_failed;
        }
 
        /* enable Interrupt */
@@ -102,7 +118,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
                goto skl_load_base_firmware_failed;
        }
 
-       ret = skl_transfer_firmware(ctx, fw->data, fw->size);
+       ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
        if (ret < 0) {
                dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
                goto skl_load_base_firmware_failed;
@@ -118,13 +134,12 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
                dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
                skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
        }
-       release_firmware(fw);
-
        return 0;
 
 skl_load_base_firmware_failed:
        skl_dsp_disable_core(ctx);
-       release_firmware(fw);
+       release_firmware(ctx->fw);
+       ctx->fw = NULL;
        return ret;
 }
 
@@ -172,6 +187,12 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
        }
        skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
 
+       /* disable Interrupt */
+       ctx->cl_dev.ops.cl_cleanup_controller(ctx);
+       skl_cldma_int_disable(ctx);
+       skl_ipc_op_int_disable(ctx);
+       skl_ipc_int_disable(ctx);
+
        return ret;
 }
 
@@ -235,22 +256,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        if (ret)
                return ret;
 
-       skl->boot_complete = false;
-       init_waitqueue_head(&skl->boot_wait);
-
-       ret = skl_dsp_boot(sst);
-       if (ret < 0) {
-               dev_err(skl->dev, "Boot dsp core failed ret: %d", ret);
-               goto free_ipc;
-       }
-
-       ret = skl_cldma_prepare(sst);
-       if (ret < 0) {
-               dev_err(dev, "CL dma prepare failed : %d", ret);
-               goto free_ipc;
-       }
-
-
        ret = sst->fw_ops.load_fw(sst);
        if (ret < 0) {
                dev_err(dev, "Load base fw failed : %d", ret);
@@ -262,7 +267,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
 
        return 0;
 
-free_ipc:
        skl_ipc_free(&skl->ipc);
        return ret;
 }
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
new file mode 100644 (file)
index 0000000..a7854c8
--- /dev/null
@@ -0,0 +1,1252 @@
+/*
+ *  skl-topology.c - Implements Platform component ALSA controls/widget
+ *  handlers.
+ *
+ *  Copyright (C) 2014-2015 Intel Corp
+ *  Author: Jeeja KP <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include <sound/soc.h>
+#include <sound/soc-topology.h>
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+#include "skl-topology.h"
+#include "skl.h"
+#include "skl-tplg-interface.h"
+
+#define SKL_CH_FIXUP_MASK              (1 << 0)
+#define SKL_RATE_FIXUP_MASK            (1 << 1)
+#define SKL_FMT_FIXUP_MASK             (1 << 2)
+
+/*
+ * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
+ * ignore. This helpers checks if the SKL driver handles this widget type
+ */
+static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
+{
+       switch (w->id) {
+       case snd_soc_dapm_dai_link:
+       case snd_soc_dapm_dai_in:
+       case snd_soc_dapm_aif_in:
+       case snd_soc_dapm_aif_out:
+       case snd_soc_dapm_dai_out:
+       case snd_soc_dapm_switch:
+               return false;
+       default:
+               return true;
+       }
+}
+
+/*
+ * Each pipelines needs memory to be allocated. Check if we have free memory
+ * from available pool. Then only add this to pool
+ * This is freed when pipe is deleted
+ * Note: DSP does actual memory management we only keep track for complete
+ * pool
+ */
+static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
+                               struct skl_module_cfg *mconfig)
+{
+       struct skl_sst *ctx = skl->skl_sst;
+
+       if (skl->resource.mem + mconfig->pipe->memory_pages >
+                               skl->resource.max_mem) {
+               dev_err(ctx->dev,
+                               "%s: module_id %d instance %d\n", __func__,
+                               mconfig->id.module_id,
+                               mconfig->id.instance_id);
+               dev_err(ctx->dev,
+                               "exceeds ppl memory available %d mem %d\n",
+                               skl->resource.max_mem, skl->resource.mem);
+               return false;
+       }
+
+       skl->resource.mem += mconfig->pipe->memory_pages;
+       return true;
+}
+
+/*
+ * Pipeline needs needs DSP CPU resources for computation, this is
+ * quantified in MCPS (Million Clocks Per Second) required for module/pipe
+ *
+ * Each pipelines needs mcps to be allocated. Check if we have mcps for this
+ * pipe. This adds the mcps to driver counter
+ * This is removed on pipeline delete
+ */
+static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
+                               struct skl_module_cfg *mconfig)
+{
+       struct skl_sst *ctx = skl->skl_sst;
+
+       if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
+               dev_err(ctx->dev,
+                       "%s: module_id %d instance %d\n", __func__,
+                       mconfig->id.module_id, mconfig->id.instance_id);
+               dev_err(ctx->dev,
+                       "exceeds ppl memory available %d > mem %d\n",
+                       skl->resource.max_mcps, skl->resource.mcps);
+               return false;
+       }
+
+       skl->resource.mcps += mconfig->mcps;
+       return true;
+}
+
+/*
+ * Free the mcps when tearing down
+ */
+static void
+skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
+{
+       skl->resource.mcps -= mconfig->mcps;
+}
+
+/*
+ * Free the memory when tearing down
+ */
+static void
+skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
+{
+       skl->resource.mem -= mconfig->pipe->memory_pages;
+}
+
+
+static void skl_dump_mconfig(struct skl_sst *ctx,
+                                       struct skl_module_cfg *mcfg)
+{
+       dev_dbg(ctx->dev, "Dumping config\n");
+       dev_dbg(ctx->dev, "Input Format:\n");
+       dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n",
+                       mcfg->in_fmt.valid_bit_depth);
+       dev_dbg(ctx->dev, "Output Format:\n");
+       dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
+       dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
+       dev_dbg(ctx->dev, "valid bit depth = %d\n",
+                       mcfg->out_fmt.valid_bit_depth);
+       dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
+}
+
+static void skl_tplg_update_params(struct skl_module_fmt *fmt,
+                       struct skl_pipe_params *params, int fixup)
+{
+       if (fixup & SKL_RATE_FIXUP_MASK)
+               fmt->s_freq = params->s_freq;
+       if (fixup & SKL_CH_FIXUP_MASK)
+               fmt->channels = params->ch;
+       if (fixup & SKL_FMT_FIXUP_MASK)
+               fmt->valid_bit_depth = params->s_fmt;
+}
+
+/*
+ * A pipeline may have modules which impact the pcm parameters, like SRC,
+ * channel converter, format converter.
+ * We need to calculate the output params by applying the 'fixup'
+ * Topology will tell driver which type of fixup is to be applied by
+ * supplying the fixup mask, so based on that we calculate the output
+ *
+ * Now In FE the pcm hw_params is source/target format. Same is applicable
+ * for BE with its hw_params invoked.
+ * here based on FE, BE pipeline and direction we calculate the input and
+ * outfix and then apply that for a module
+ */
+static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
+               struct skl_pipe_params *params, bool is_fe)
+{
+       int in_fixup, out_fixup;
+       struct skl_module_fmt *in_fmt, *out_fmt;
+
+       in_fmt = &m_cfg->in_fmt;
+       out_fmt = &m_cfg->out_fmt;
+
+       if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (is_fe) {
+                       in_fixup = m_cfg->params_fixup;
+                       out_fixup = (~m_cfg->converter) &
+                                       m_cfg->params_fixup;
+               } else {
+                       out_fixup = m_cfg->params_fixup;
+                       in_fixup = (~m_cfg->converter) &
+                                       m_cfg->params_fixup;
+               }
+       } else {
+               if (is_fe) {
+                       out_fixup = m_cfg->params_fixup;
+                       in_fixup = (~m_cfg->converter) &
+                                       m_cfg->params_fixup;
+               } else {
+                       in_fixup = m_cfg->params_fixup;
+                       out_fixup = (~m_cfg->converter) &
+                                       m_cfg->params_fixup;
+               }
+       }
+
+       skl_tplg_update_params(in_fmt, params, in_fixup);
+       skl_tplg_update_params(out_fmt, params, out_fixup);
+}
+
+/*
+ * A module needs input and output buffers, which are dependent upon pcm
+ * params, so once we have calculate params, we need buffer calculation as
+ * well.
+ */
+static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
+                               struct skl_module_cfg *mcfg)
+{
+       int multiplier = 1;
+
+       if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
+               multiplier = 5;
+
+       mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
+                               (mcfg->in_fmt.channels) *
+                               (mcfg->in_fmt.bit_depth >> 3) *
+                               multiplier;
+
+       mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
+                               (mcfg->out_fmt.channels) *
+                               (mcfg->out_fmt.bit_depth >> 3) *
+                               multiplier;
+}
+
+static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
+                                                       struct skl_sst *ctx)
+{
+       struct skl_module_cfg *m_cfg = w->priv;
+       struct skl_pipe_params *params = m_cfg->pipe->p_params;
+       int p_conn_type = m_cfg->pipe->conn_type;
+       bool is_fe;
+
+       if (!m_cfg->params_fixup)
+               return;
+
+       dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
+                               w->name);
+
+       skl_dump_mconfig(ctx, m_cfg);
+
+       if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
+               is_fe = true;
+       else
+               is_fe = false;
+
+       skl_tplg_update_params_fixup(m_cfg, params, is_fe);
+       skl_tplg_update_buffer_size(ctx, m_cfg);
+
+       dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
+                               w->name);
+
+       skl_dump_mconfig(ctx, m_cfg);
+}
+
+/*
+ * A pipe can have multiple modules, each of them will be a DAPM widget as
+ * well. While managing a pipeline we need to get the list of all the
+ * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps
+ * to get the SKL type widgets in that pipeline
+ */
+static int skl_tplg_alloc_pipe_widget(struct device *dev,
+       struct snd_soc_dapm_widget *w, struct skl_pipe *pipe)
+{
+       struct skl_module_cfg *src_module = NULL;
+       struct snd_soc_dapm_path *p = NULL;
+       struct skl_pipe_module *p_module = NULL;
+
+       p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL);
+       if (!p_module)
+               return -ENOMEM;
+
+       p_module->w = w;
+       list_add_tail(&p_module->node, &pipe->w_list);
+
+       snd_soc_dapm_widget_for_each_sink_path(w, p) {
+               if ((p->sink->priv == NULL)
+                               && (!is_skl_dsp_widget_type(w)))
+                       continue;
+
+               if ((p->sink->priv != NULL) && p->connect
+                               && is_skl_dsp_widget_type(p->sink)) {
+
+                       src_module = p->sink->priv;
+                       if (pipe->ppl_id == src_module->pipe->ppl_id)
+                               skl_tplg_alloc_pipe_widget(dev,
+                                                       p->sink, pipe);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Inside a pipe instance, we can have various modules. These modules need
+ * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
+ * skl_init_module() routine, so invoke that for all modules in a pipeline
+ */
+static int
+skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
+{
+       struct skl_pipe_module *w_module;
+       struct snd_soc_dapm_widget *w;
+       struct skl_module_cfg *mconfig;
+       struct skl_sst *ctx = skl->skl_sst;
+       int ret = 0;
+
+       list_for_each_entry(w_module, &pipe->w_list, node) {
+               w = w_module->w;
+               mconfig = w->priv;
+
+               /* check resource available */
+               if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+                       return -ENOMEM;
+
+               /*
+                * apply fix/conversion to module params based on
+                * FE/BE params
+                */
+               skl_tplg_update_module_params(w, ctx);
+               ret = skl_init_module(ctx, mconfig, NULL);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
+ * need create the pipeline. So we do following:
+ *   - check the resources
+ *   - Create the pipeline
+ *   - Initialize the modules in pipeline
+ *   - finally bind all modules together
+ */
+static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
+                                                       struct skl *skl)
+{
+       int ret;
+       struct skl_module_cfg *mconfig = w->priv;
+       struct skl_pipe_module *w_module;
+       struct skl_pipe *s_pipe = mconfig->pipe;
+       struct skl_module_cfg *src_module = NULL, *dst_module;
+       struct skl_sst *ctx = skl->skl_sst;
+
+       /* check resource available */
+       if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+               return -EBUSY;
+
+       if (!skl_tplg_alloc_pipe_mem(skl, mconfig))
+               return -ENOMEM;
+
+       /*
+        * Create a list of modules for pipe.
+        * This list contains modules from source to sink
+        */
+       ret = skl_create_pipeline(ctx, mconfig->pipe);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * we create a w_list of all widgets in that pipe. This list is not
+        * freed on PMD event as widgets within a pipe are static. This
+        * saves us cycles to get widgets in pipe every time.
+        *
+        * So if we have already initialized all the widgets of a pipeline
+        * we skip, so check for list_empty and create the list if empty
+        */
+       if (list_empty(&s_pipe->w_list)) {
+               ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Init all pipe modules from source to sink */
+       ret = skl_tplg_init_pipe_modules(skl, s_pipe);
+       if (ret < 0)
+               return ret;
+
+       /* Bind modules from source to sink */
+       list_for_each_entry(w_module, &s_pipe->w_list, node) {
+               dst_module = w_module->w->priv;
+
+               if (src_module == NULL) {
+                       src_module = dst_module;
+                       continue;
+               }
+
+               ret = skl_bind_modules(ctx, src_module, dst_module);
+               if (ret < 0)
+                       return ret;
+
+               src_module = dst_module;
+       }
+
+       return 0;
+}
+
+/*
+ * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
+ * we need to do following:
+ *   - Bind to sink pipeline
+ *      Since the sink pipes can be running and we don't get mixer event on
+ *      connect for already running mixer, we need to find the sink pipes
+ *      here and bind to them. This way dynamic connect works.
+ *   - Start sink pipeline, if not running
+ *   - Then run current pipe
+ */
+static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
+                                                       struct skl *skl)
+{
+       struct snd_soc_dapm_path *p;
+       struct skl_dapm_path_list *path_list;
+       struct snd_soc_dapm_widget *source, *sink;
+       struct skl_module_cfg *src_mconfig, *sink_mconfig;
+       struct skl_sst *ctx = skl->skl_sst;
+       int ret = 0;
+
+       source = w;
+       src_mconfig = source->priv;
+
+       /*
+        * find which sink it is connected to, bind with the sink,
+        * if sink is not started, start sink pipe first, then start
+        * this pipe
+        */
+       snd_soc_dapm_widget_for_each_source_path(w, p) {
+               if (!p->connect)
+                       continue;
+
+               dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
+               dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
+
+               /*
+                * here we will check widgets in sink pipelines, so that
+                * can be any widgets type and we are only interested if
+                * they are ones used for SKL so check that first
+                */
+               if ((p->sink->priv != NULL) &&
+                                       is_skl_dsp_widget_type(p->sink)) {
+
+                       sink = p->sink;
+                       src_mconfig = source->priv;
+                       sink_mconfig = sink->priv;
+
+                       /* Bind source to sink, mixin is always source */
+                       ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
+                       if (ret)
+                               return ret;
+
+                       /* Start sinks pipe first */
+                       if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
+                               ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+                               if (ret)
+                                       return ret;
+                       }
+
+                       path_list = kzalloc(
+                                       sizeof(struct skl_dapm_path_list),
+                                       GFP_KERNEL);
+                       if (path_list == NULL)
+                               return -ENOMEM;
+
+                       /* Add connected path to one global list */
+                       path_list->dapm_path = p;
+                       list_add_tail(&path_list->node, &skl->dapm_path_list);
+                       break;
+               }
+       }
+
+       /* Start source pipe last after starting all sinks */
+       ret = skl_run_pipe(ctx, src_mconfig->pipe);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * in the Post-PMU event of mixer we need to do following:
+ *   - Check if this pipe is running
+ *   - if not, then
+ *     - bind this pipeline to its source pipeline
+ *       if source pipe is already running, this means it is a dynamic
+ *       connection and we need to bind only to that pipe
+ *     - start this pipeline
+ */
+static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
+                                                       struct skl *skl)
+{
+       int ret = 0;
+       struct snd_soc_dapm_path *p;
+       struct snd_soc_dapm_widget *source, *sink;
+       struct skl_module_cfg *src_mconfig, *sink_mconfig;
+       struct skl_sst *ctx = skl->skl_sst;
+       int src_pipe_started = 0;
+
+       sink = w;
+       sink_mconfig = sink->priv;
+
+       /*
+        * If source pipe is already started, that means source is driving
+        * one more sink before this sink got connected, Since source is
+        * started, bind this sink to source and start this pipe.
+        */
+       snd_soc_dapm_widget_for_each_sink_path(w, p) {
+               if (!p->connect)
+                       continue;
+
+               dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
+               dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+
+               /*
+                * here we will check widgets in sink pipelines, so that
+                * can be any widgets type and we are only interested if
+                * they are ones used for SKL so check that first
+                */
+               if ((p->source->priv != NULL) &&
+                                       is_skl_dsp_widget_type(p->source)) {
+                       source = p->source;
+                       src_mconfig = source->priv;
+                       sink_mconfig = sink->priv;
+                       src_pipe_started = 1;
+
+                       /*
+                        * check pipe state, then no need to bind or start
+                        * the pipe
+                        */
+                       if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
+                               src_pipe_started = 0;
+               }
+       }
+
+       if (src_pipe_started) {
+               ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
+               if (ret)
+                       return ret;
+
+               ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+       }
+
+       return ret;
+}
+
+/*
+ * in the Pre-PMD event of mixer we need to do following:
+ *   - Stop the pipe
+ *   - find the source connections and remove that from dapm_path_list
+ *   - unbind with source pipelines if still connected
+ */
+static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
+                                                       struct skl *skl)
+{
+       struct snd_soc_dapm_widget *source, *sink;
+       struct skl_module_cfg *src_mconfig, *sink_mconfig;
+       int ret = 0, path_found = 0;
+       struct skl_dapm_path_list *path_list, *tmp_list;
+       struct skl_sst *ctx = skl->skl_sst;
+
+       sink = w;
+       sink_mconfig = sink->priv;
+
+       /* Stop the pipe */
+       ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
+       if (ret)
+               return ret;
+
+       /*
+        * This list, dapm_path_list handling here does not need any locks
+        * as we are under dapm lock while handling widget events.
+        * List can be manipulated safely only under dapm widgets handler
+        * routines
+        */
+       list_for_each_entry_safe(path_list, tmp_list,
+                               &skl->dapm_path_list, node) {
+               if (path_list->dapm_path->sink == sink) {
+                       dev_dbg(ctx->dev, "Path found = %s\n",
+                                       path_list->dapm_path->name);
+                       source = path_list->dapm_path->source;
+                       src_mconfig = source->priv;
+                       path_found = 1;
+
+                       list_del(&path_list->node);
+                       kfree(path_list);
+                       break;
+               }
+       }
+
+       /*
+        * If path_found == 1, that means pmd for source pipe has
+        * not occurred, source is connected to some other sink.
+        * so its responsibility of sink to unbind itself from source.
+        */
+       if (path_found) {
+               ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+               if (ret < 0)
+                       return ret;
+
+               ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
+       }
+
+       return ret;
+}
+
+/*
+ * in the Post-PMD event of mixer we need to do following:
+ *   - Free the mcps used
+ *   - Free the mem used
+ *   - Unbind the modules within the pipeline
+ *   - Delete the pipeline (modules are not required to be explicitly
+ *     deleted, pipeline delete is enough here
+ */
+static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
+                                                       struct skl *skl)
+{
+       struct skl_module_cfg *mconfig = w->priv;
+       struct skl_pipe_module *w_module;
+       struct skl_module_cfg *src_module = NULL, *dst_module;
+       struct skl_sst *ctx = skl->skl_sst;
+       struct skl_pipe *s_pipe = mconfig->pipe;
+       int ret = 0;
+
+       skl_tplg_free_pipe_mcps(skl, mconfig);
+
+       list_for_each_entry(w_module, &s_pipe->w_list, node) {
+               dst_module = w_module->w->priv;
+
+               if (src_module == NULL) {
+                       src_module = dst_module;
+                       continue;
+               }
+
+               ret = skl_unbind_modules(ctx, src_module, dst_module);
+               if (ret < 0)
+                       return ret;
+
+               src_module = dst_module;
+       }
+
+       ret = skl_delete_pipe(ctx, mconfig->pipe);
+       skl_tplg_free_pipe_mem(skl, mconfig);
+
+       return ret;
+}
+
+/*
+ * in the Post-PMD event of PGA we need to do following:
+ *   - Free the mcps used
+ *   - Stop the pipeline
+ *   - In source pipe is connected, unbind with source pipelines
+ */
+static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
+                                                               struct skl *skl)
+{
+       struct snd_soc_dapm_widget *source, *sink;
+       struct skl_module_cfg *src_mconfig, *sink_mconfig;
+       int ret = 0, path_found = 0;
+       struct skl_dapm_path_list *path_list, *tmp_path_list;
+       struct skl_sst *ctx = skl->skl_sst;
+
+       source = w;
+       src_mconfig = source->priv;
+
+       skl_tplg_free_pipe_mcps(skl, src_mconfig);
+       /* Stop the pipe since this is a mixin module */
+       ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+       if (ret)
+               return ret;
+
+       list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) {
+               if (path_list->dapm_path->source == source) {
+                       dev_dbg(ctx->dev, "Path found = %s\n",
+                                       path_list->dapm_path->name);
+                       sink = path_list->dapm_path->sink;
+                       sink_mconfig = sink->priv;
+                       path_found = 1;
+
+                       list_del(&path_list->node);
+                       kfree(path_list);
+                       break;
+               }
+       }
+
+       /*
+        * This is a connector and if path is found that means
+        * unbind between source and sink has not happened yet
+        */
+       if (path_found) {
+               ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+               if (ret < 0)
+                       return ret;
+
+               ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
+       }
+
+       return ret;
+}
+
+/*
+ * In modelling, we assume there will be ONLY one mixer in a pipeline.  If
+ * mixer is not required then it is treated as static mixer aka vmixer with
+ * a hard path to source module
+ * So we don't need to check if source is started or not as hard path puts
+ * dependency on each other
+ */
+static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct skl *skl = get_skl_ctx(dapm->dev);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
+
+       case SND_SOC_DAPM_POST_PMD:
+               return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
+       }
+
+       return 0;
+}
+
+/*
+ * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
+ * second one is required that is created as another pipe entity.
+ * The mixer is responsible for pipe management and represent a pipeline
+ * instance
+ */
+static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct skl *skl = get_skl_ctx(dapm->dev);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
+
+       case SND_SOC_DAPM_POST_PMU:
+               return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
+
+       case SND_SOC_DAPM_PRE_PMD:
+               return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
+
+       case SND_SOC_DAPM_POST_PMD:
+               return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
+       }
+
+       return 0;
+}
+
+/*
+ * In modelling, we assumed rest of the modules in pipeline are PGA. But we
+ * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
+ * the sink when it is running (two FE to one BE or one FE to two BE)
+ * scenarios
+ */
+static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct skl *skl = get_skl_ctx(dapm->dev);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
+
+       case SND_SOC_DAPM_POST_PMD:
+               return skl_tplg_pga_dapm_post_pmd_event(w, skl);
+       }
+
+       return 0;
+}
+
+/*
+ * The FE params are passed by hw_params of the DAI.
+ * On hw_params, the params are stored in Gateway module of the FE and we
+ * need to calculate the format in DSP module configuration, that
+ * conversion is done here
+ */
+int skl_tplg_update_pipe_params(struct device *dev,
+                       struct skl_module_cfg *mconfig,
+                       struct skl_pipe_params *params)
+{
+       struct skl_pipe *pipe = mconfig->pipe;
+       struct skl_module_fmt *format = NULL;
+
+       memcpy(pipe->p_params, params, sizeof(*params));
+
+       if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               format = &mconfig->in_fmt;
+       else
+               format = &mconfig->out_fmt;
+
+       /* set the hw_params */
+       format->s_freq = params->s_freq;
+       format->channels = params->ch;
+       format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
+
+       /*
+        * 16 bit is 16 bit container whereas 24 bit is in 32 bit
+        * container so update bit depth accordingly
+        */
+       switch (format->valid_bit_depth) {
+       case SKL_DEPTH_16BIT:
+               format->bit_depth = format->valid_bit_depth;
+               break;
+
+       case SKL_DEPTH_24BIT:
+               format->bit_depth = SKL_DEPTH_32BIT;
+               break;
+
+       default:
+               dev_err(dev, "Invalid bit depth %x for pipe\n",
+                               format->valid_bit_depth);
+               return -EINVAL;
+       }
+
+       if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               mconfig->ibs = (format->s_freq / 1000) *
+                               (format->channels) *
+                               (format->bit_depth >> 3);
+       } else {
+               mconfig->obs = (format->s_freq / 1000) *
+                               (format->channels) *
+                               (format->bit_depth >> 3);
+       }
+
+       return 0;
+}
+
+/*
+ * Query the module config for the FE DAI
+ * This is used to find the hw_params set for that DAI and apply to FE
+ * pipeline
+ */
+struct skl_module_cfg *
+skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
+{
+       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_path *p = NULL;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               w = dai->playback_widget;
+               snd_soc_dapm_widget_for_each_sink_path(w, p) {
+                       if (p->connect && p->sink->power &&
+                                       is_skl_dsp_widget_type(p->sink))
+                               continue;
+
+                       if (p->sink->priv) {
+                               dev_dbg(dai->dev, "set params for %s\n",
+                                               p->sink->name);
+                               return p->sink->priv;
+                       }
+               }
+       } else {
+               w = dai->capture_widget;
+               snd_soc_dapm_widget_for_each_source_path(w, p) {
+                       if (p->connect && p->source->power &&
+                                       is_skl_dsp_widget_type(p->source))
+                               continue;
+
+                       if (p->source->priv) {
+                               dev_dbg(dai->dev, "set params for %s\n",
+                                               p->source->name);
+                               return p->source->priv;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static u8 skl_tplg_be_link_type(int dev_type)
+{
+       int ret;
+
+       switch (dev_type) {
+       case SKL_DEVICE_BT:
+               ret = NHLT_LINK_SSP;
+               break;
+
+       case SKL_DEVICE_DMIC:
+               ret = NHLT_LINK_DMIC;
+               break;
+
+       case SKL_DEVICE_I2S:
+               ret = NHLT_LINK_SSP;
+               break;
+
+       case SKL_DEVICE_HDALINK:
+               ret = NHLT_LINK_HDA;
+               break;
+
+       default:
+               ret = NHLT_LINK_INVALID;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Fill the BE gateway parameters
+ * The BE gateway expects a blob of parameters which are kept in the ACPI
+ * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
+ * The port can have multiple settings so pick based on the PCM
+ * parameters
+ */
+static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
+                               struct skl_module_cfg *mconfig,
+                               struct skl_pipe_params *params)
+{
+       struct skl_pipe *pipe = mconfig->pipe;
+       struct nhlt_specific_cfg *cfg;
+       struct skl *skl = get_skl_ctx(dai->dev);
+       int link_type = skl_tplg_be_link_type(mconfig->dev_type);
+
+       memcpy(pipe->p_params, params, sizeof(*params));
+
+       /* update the blob based on virtual bus_id*/
+       cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
+                                       params->s_fmt, params->ch,
+                                       params->s_freq, params->stream);
+       if (cfg) {
+               mconfig->formats_config.caps_size = cfg->size;
+               mconfig->formats_config.caps = (u32 *) &cfg->caps;
+       } else {
+               dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
+                                       mconfig->vbus_id, link_type,
+                                       params->stream);
+               dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
+                                params->ch, params->s_freq, params->s_fmt);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
+                               struct snd_soc_dapm_widget *w,
+                               struct skl_pipe_params *params)
+{
+       struct snd_soc_dapm_path *p;
+       int ret = -EIO;
+
+       snd_soc_dapm_widget_for_each_source_path(w, p) {
+               if (p->connect && is_skl_dsp_widget_type(p->source) &&
+                                               p->source->priv) {
+
+                       if (!p->source->power) {
+                               ret = skl_tplg_be_fill_pipe_params(
+                                               dai, p->source->priv,
+                                               params);
+                               if (ret < 0)
+                                       return ret;
+                       } else {
+                               return -EBUSY;
+                       }
+               } else {
+                       ret = skl_tplg_be_set_src_pipe_params(
+                                               dai, p->source, params);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
+       struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
+{
+       struct snd_soc_dapm_path *p = NULL;
+       int ret = -EIO;
+
+       snd_soc_dapm_widget_for_each_sink_path(w, p) {
+               if (p->connect && is_skl_dsp_widget_type(p->sink) &&
+                                               p->sink->priv) {
+
+                       if (!p->sink->power) {
+                               ret = skl_tplg_be_fill_pipe_params(
+                                               dai, p->sink->priv, params);
+                               if (ret < 0)
+                                       return ret;
+                       } else {
+                               return -EBUSY;
+                       }
+
+               } else {
+                       ret = skl_tplg_be_set_sink_pipe_params(
+                                               dai, p->sink, params);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * BE hw_params can be a source parameters (capture) or sink parameters
+ * (playback). Based on sink and source we need to either find the source
+ * list or the sink list and set the pipeline parameters
+ */
+int skl_tplg_be_update_params(struct snd_soc_dai *dai,
+                               struct skl_pipe_params *params)
+{
+       struct snd_soc_dapm_widget *w;
+
+       if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               w = dai->playback_widget;
+
+               return skl_tplg_be_set_src_pipe_params(dai, w, params);
+
+       } else {
+               w = dai->capture_widget;
+
+               return skl_tplg_be_set_sink_pipe_params(dai, w, params);
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
+       {SKL_MIXER_EVENT, skl_tplg_mixer_event},
+       {SKL_VMIXER_EVENT, skl_tplg_vmixer_event},
+       {SKL_PGA_EVENT, skl_tplg_pga_event},
+};
+
+/*
+ * The topology binary passes the pin info for a module so initialize the pin
+ * info passed into module instance
+ */
+static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
+                                               struct skl_module_pin *m_pin,
+                                               bool is_dynamic, int max_pin)
+{
+       int i;
+
+       for (i = 0; i < max_pin; i++) {
+               m_pin[i].id.module_id = dfw_pin[i].module_id;
+               m_pin[i].id.instance_id = dfw_pin[i].instance_id;
+               m_pin[i].in_use = false;
+               m_pin[i].is_dynamic = is_dynamic;
+       }
+}
+
+/*
+ * Add pipeline from topology binary into driver pipeline list
+ *
+ * If already added we return that instance
+ * Otherwise we create a new instance and add into driver list
+ */
+static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
+                       struct skl *skl, struct skl_dfw_pipe *dfw_pipe)
+{
+       struct skl_pipeline *ppl;
+       struct skl_pipe *pipe;
+       struct skl_pipe_params *params;
+
+       list_for_each_entry(ppl, &skl->ppl_list, node) {
+               if (ppl->pipe->ppl_id == dfw_pipe->pipe_id)
+                       return ppl->pipe;
+       }
+
+       ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
+       if (!ppl)
+               return NULL;
+
+       pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
+       if (!pipe)
+               return NULL;
+
+       params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
+       if (!params)
+               return NULL;
+
+       pipe->ppl_id = dfw_pipe->pipe_id;
+       pipe->memory_pages = dfw_pipe->memory_pages;
+       pipe->pipe_priority = dfw_pipe->pipe_priority;
+       pipe->conn_type = dfw_pipe->conn_type;
+       pipe->state = SKL_PIPE_INVALID;
+       pipe->p_params = params;
+       INIT_LIST_HEAD(&pipe->w_list);
+
+       ppl->pipe = pipe;
+       list_add(&ppl->node, &skl->ppl_list);
+
+       return ppl->pipe;
+}
+
+/*
+ * Topology core widget load callback
+ *
+ * This is used to save the private data for each widget which gives
+ * information to the driver about module and pipeline parameters which DSP
+ * FW expects like ids, resource values, formats etc
+ */
+static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
+                               struct snd_soc_dapm_widget *w,
+                               struct snd_soc_tplg_dapm_widget *tplg_w)
+{
+       int ret;
+       struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
+       struct skl *skl = ebus_to_skl(ebus);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl_module_cfg *mconfig;
+       struct skl_pipe *pipe;
+       struct skl_dfw_module *dfw_config =
+                               (struct skl_dfw_module *)tplg_w->priv.data;
+
+       if (!tplg_w->priv.size)
+               goto bind_event;
+
+       mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
+
+       if (!mconfig)
+               return -ENOMEM;
+
+       w->priv = mconfig;
+       mconfig->id.module_id = dfw_config->module_id;
+       mconfig->id.instance_id = dfw_config->instance_id;
+       mconfig->mcps = dfw_config->max_mcps;
+       mconfig->ibs = dfw_config->ibs;
+       mconfig->obs = dfw_config->obs;
+       mconfig->core_id = dfw_config->core_id;
+       mconfig->max_in_queue = dfw_config->max_in_queue;
+       mconfig->max_out_queue = dfw_config->max_out_queue;
+       mconfig->is_loadable = dfw_config->is_loadable;
+       mconfig->in_fmt.channels = dfw_config->in_fmt.channels;
+       mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq;
+       mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth;
+       mconfig->in_fmt.valid_bit_depth =
+                               dfw_config->in_fmt.valid_bit_depth;
+       mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg;
+       mconfig->out_fmt.channels = dfw_config->out_fmt.channels;
+       mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq;
+       mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth;
+       mconfig->out_fmt.valid_bit_depth =
+                               dfw_config->out_fmt.valid_bit_depth;
+       mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg;
+       mconfig->params_fixup = dfw_config->params_fixup;
+       mconfig->converter = dfw_config->converter;
+       mconfig->m_type = dfw_config->module_type;
+       mconfig->vbus_id = dfw_config->vbus_id;
+
+       pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
+       if (pipe)
+               mconfig->pipe = pipe;
+
+       mconfig->dev_type = dfw_config->dev_type;
+       mconfig->hw_conn_type = dfw_config->hw_conn_type;
+       mconfig->time_slot = dfw_config->time_slot;
+       mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
+
+       mconfig->m_in_pin = devm_kzalloc(bus->dev,
+                               (mconfig->max_in_queue) *
+                                       sizeof(*mconfig->m_in_pin),
+                               GFP_KERNEL);
+       if (!mconfig->m_in_pin)
+               return -ENOMEM;
+
+       mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) *
+                                               sizeof(*mconfig->m_out_pin),
+                                               GFP_KERNEL);
+       if (!mconfig->m_out_pin)
+               return -ENOMEM;
+
+       skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin,
+                                               dfw_config->is_dynamic_in_pin,
+                                               mconfig->max_in_queue);
+
+       skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin,
+                                                dfw_config->is_dynamic_out_pin,
+                                                       mconfig->max_out_queue);
+
+
+       if (mconfig->formats_config.caps_size == 0)
+               goto bind_event;
+
+       mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev,
+                       mconfig->formats_config.caps_size, GFP_KERNEL);
+
+       if (mconfig->formats_config.caps == NULL)
+               return -ENOMEM;
+
+       memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
+                                        dfw_config->caps.caps_size);
+
+bind_event:
+       if (tplg_w->event_type == 0) {
+               dev_dbg(bus->dev, "ASoC: No event handler required\n");
+               return 0;
+       }
+
+       ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
+                                       ARRAY_SIZE(skl_tplg_widget_ops),
+                                       tplg_w->event_type);
+
+       if (ret) {
+               dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
+                                       __func__, tplg_w->event_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_tplg_ops skl_tplg_ops  = {
+       .widget_load = skl_tplg_widget_load,
+};
+
+/* This will be read from topology manifest, currently defined here */
+#define SKL_MAX_MCPS 30000000
+#define SKL_FW_MAX_MEM 1000000
+
+/*
+ * SKL topology init routine
+ */
+int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
+{
+       int ret;
+       const struct firmware *fw;
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = ebus_to_skl(ebus);
+
+       ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
+       if (ret < 0) {
+               dev_err(bus->dev, "tplg fw %s load failed with %d\n",
+                               "dfw_sst.bin", ret);
+               return ret;
+       }
+
+       /*
+        * The complete tplg for SKL is loaded as index 0, we don't use
+        * any other index
+        */
+       ret = snd_soc_tplg_component_load(&platform->component,
+                                       &skl_tplg_ops, fw, 0);
+       if (ret < 0) {
+               dev_err(bus->dev, "tplg component load failed%d\n", ret);
+               return -EINVAL;
+       }
+
+       skl->resource.max_mcps = SKL_MAX_MCPS;
+       skl->resource.max_mem = SKL_FW_MAX_MEM;
+
+       return 0;
+}
index 8c7767baa94fbe44239f425b48dbd6c6ecf643a8..76053a8de41cf255bfe77d24673c320cf5d2fd0a 100644 (file)
@@ -129,6 +129,11 @@ struct skl_src_module_cfg {
        enum skl_s_freq src_cfg;
 } __packed;
 
+struct notification_mask {
+       u32 notify;
+       u32 enable;
+} __packed;
+
 struct skl_up_down_mixer_cfg {
        struct skl_base_cfg base_cfg;
        enum skl_ch_cfg out_ch_cfg;
@@ -153,8 +158,7 @@ enum skl_dma_type {
 union skl_ssp_dma_node {
        u8 val;
        struct {
-               u8 dual_mono:1;
-               u8 time_slot:3;
+               u8 time_slot_index:4;
                u8 i2s_instance:4;
        } dma_node;
 };
@@ -263,6 +267,34 @@ struct skl_module_cfg {
        struct skl_specific_cfg formats_config;
 };
 
+struct skl_pipeline {
+       struct skl_pipe *pipe;
+       struct list_head node;
+};
+
+struct skl_dapm_path_list {
+       struct snd_soc_dapm_path *dapm_path;
+       struct list_head node;
+};
+
+static inline struct skl *get_skl_ctx(struct device *dev)
+{
+       struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+
+       return ebus_to_skl(ebus);
+}
+
+int skl_tplg_be_update_params(struct snd_soc_dai *dai,
+       struct skl_pipe_params *params);
+void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
+       struct skl_pipe_params *params, int stream);
+int skl_tplg_init(struct snd_soc_platform *platform,
+                               struct hdac_ext_bus *ebus);
+struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
+               struct snd_soc_dai *dai, int stream);
+int skl_tplg_update_pipe_params(struct device *dev,
+               struct skl_module_cfg *mconfig, struct skl_pipe_params *params);
+
 int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
index a50689825bcace5836d41f931155cf0fdacdc454..2bc396d54cbed52fa257c1c499749eaed8ebc111 100644 (file)
 #ifndef __HDA_TPLG_INTERFACE_H__
 #define __HDA_TPLG_INTERFACE_H__
 
+/*
+ * Default types range from 0~12. type can range from 0 to 0xff
+ * SST types start at higher to avoid any overlapping in future
+ */
+#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS   0x100
+#define SOC_CONTROL_TYPE_HDA_SST_MUX           0x101
+#define SOC_CONTROL_TYPE_HDA_SST_MIX           0x101
+#define SOC_CONTROL_TYPE_HDA_SST_BYTE          0x103
+
+#define HDA_SST_CFG_MAX        900 /* size of copier cfg*/
+#define MAX_IN_QUEUE 8
+#define MAX_OUT_QUEUE 8
+
+/* Event types goes here */
+/* Reserve event type 0 for no event handlers */
+enum skl_event_types {
+       SKL_EVENT_NONE = 0,
+       SKL_MIXER_EVENT,
+       SKL_MUX_EVENT,
+       SKL_VMIXER_EVENT,
+       SKL_PGA_EVENT
+};
+
 /**
  * enum skl_ch_cfg - channel configuration
  *
@@ -83,6 +106,66 @@ enum skl_dev_type {
        SKL_DEVICE_I2S = 0x2,
        SKL_DEVICE_SLIMBUS = 0x3,
        SKL_DEVICE_HDALINK = 0x4,
+       SKL_DEVICE_HDAHOST = 0x5,
        SKL_DEVICE_NONE
 };
+
+struct skl_dfw_module_pin {
+       u16 module_id;
+       u16 instance_id;
+} __packed;
+
+struct skl_dfw_module_fmt {
+       u32 channels;
+       u32 freq;
+       u32 bit_depth;
+       u32 valid_bit_depth;
+       u32 ch_cfg;
+} __packed;
+
+struct skl_dfw_module_caps {
+       u32 caps_size;
+       u32 caps[HDA_SST_CFG_MAX];
+};
+
+struct skl_dfw_pipe {
+       u8 pipe_id;
+       u8 pipe_priority;
+       u16 conn_type;
+       u32 memory_pages;
+} __packed;
+
+struct skl_dfw_module {
+       u16 module_id;
+       u16 instance_id;
+       u32 max_mcps;
+       u8 core_id;
+       u8 max_in_queue;
+       u8 max_out_queue;
+       u8 is_loadable;
+       u8 conn_type;
+       u8 dev_type;
+       u8 hw_conn_type;
+       u8 time_slot;
+       u32 obs;
+       u32 ibs;
+       u32 params_fixup;
+       u32 converter;
+       u32 module_type;
+       u32 vbus_id;
+       u8 is_dynamic_in_pin;
+       u8 is_dynamic_out_pin;
+       struct skl_dfw_pipe pipe;
+       struct skl_dfw_module_fmt in_fmt;
+       struct skl_dfw_module_fmt out_fmt;
+       struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
+       struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
+       struct skl_dfw_module_caps caps;
+} __packed;
+
+struct skl_dfw_algo_data {
+       u32 max;
+       char *params;
+} __packed;
+
 #endif
index 348d094e81d6609ee95505ce91e9d41671032bb6..5319529aedf7ae5030dbf47ce9b6056512f05c2d 100644 (file)
@@ -166,12 +166,20 @@ static int skl_runtime_suspend(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
+       struct skl *skl = ebus_to_skl(ebus);
+       int ret;
 
        dev_dbg(bus->dev, "in %s\n", __func__);
 
        /* enable controller wake up event */
        snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
 
+       snd_hdac_ext_bus_link_power_down_all(ebus);
+
+       ret = skl_suspend_dsp(skl);
+       if (ret < 0)
+               return ret;
+
        snd_hdac_bus_stop_chip(bus);
        snd_hdac_bus_enter_link_reset(bus);
 
@@ -183,7 +191,7 @@ static int skl_runtime_resume(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
-       struct skl *hda = ebus_to_skl(ebus);
+       struct skl *skl = ebus_to_skl(ebus);
        int status;
 
        dev_dbg(bus->dev, "in %s\n", __func__);
@@ -191,12 +199,12 @@ static int skl_runtime_resume(struct device *dev)
        /* Read STATESTS before controller reset */
        status = snd_hdac_chip_readw(bus, STATESTS);
 
-       skl_init_pci(hda);
+       skl_init_pci(skl);
        snd_hdac_bus_init_chip(bus, true);
        /* disable controller Wake Up event */
        snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
 
-       return 0;
+       return skl_resume_dsp(skl);
 }
 #endif /* CONFIG_PM */
 
@@ -453,21 +461,28 @@ static int skl_probe(struct pci_dev *pci,
        if (err < 0)
                goto out_free;
 
+       skl->nhlt = skl_nhlt_init(bus->dev);
+
+       if (skl->nhlt == NULL)
+               goto out_free;
+
        pci_set_drvdata(skl->pci, ebus);
 
        /* check if dsp is there */
        if (ebus->ppcap) {
-               /* TODO register with dsp IPC */
-               dev_dbg(bus->dev, "Register dsp\n");
+               err = skl_init_dsp(skl);
+               if (err < 0) {
+                       dev_dbg(bus->dev, "error failed to register dsp\n");
+                       goto out_free;
+               }
        }
-
        if (ebus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(ebus);
 
        /* create device for soc dmic */
        err = skl_dmic_device_register(skl);
        if (err < 0)
-               goto out_free;
+               goto out_dsp_free;
 
        /* register platform dai and controls */
        err = skl_platform_register(bus->dev);
@@ -491,6 +506,8 @@ out_unregister:
        skl_platform_unregister(bus->dev);
 out_dmic_free:
        skl_dmic_device_unregister(skl);
+out_dsp_free:
+       skl_free_dsp(skl);
 out_free:
        skl->init_failed = 1;
        skl_free(ebus);
@@ -507,6 +524,7 @@ static void skl_remove(struct pci_dev *pci)
                pm_runtime_get_noresume(&pci->dev);
        pci_dev_put(pci);
        skl_platform_unregister(&pci->dev);
+       skl_free_dsp(skl);
        skl_dmic_device_unregister(skl);
        skl_free(ebus);
        dev_set_drvdata(&pci->dev, NULL);
index f7fdbb02947f79952bcb9e16ac41be3342a2bd86..dd2e79ae45a8e6294c2766ef5eff7f4fac37befe 100644 (file)
 #define AZX_REG_VS_SDXEFIFOS_XBASE     0x1094
 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
 
+struct skl_dsp_resource {
+       u32 max_mcps;
+       u32 max_mem;
+       u32 mcps;
+       u32 mem;
+};
+
 struct skl {
        struct hdac_ext_bus ebus;
        struct pci_dev *pci;
@@ -55,8 +62,12 @@ struct skl {
        unsigned int init_failed:1; /* delayed init failed */
        struct platform_device *dmic_dev;
 
-       void __iomem *nhlt; /* nhlt ptr */
+       void *nhlt; /* nhlt ptr */
        struct skl_sst *skl_sst; /* sst skl ctx */
+
+       struct skl_dsp_resource resource;
+       struct list_head ppl_list;
+       struct list_head dapm_path_list;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)
@@ -72,8 +83,8 @@ struct skl_dma_params {
 int skl_platform_unregister(struct device *dev);
 int skl_platform_register(struct device *dev);
 
-void __iomem *skl_nhlt_init(struct device *dev);
-void skl_nhlt_free(void __iomem *addr);
+void *skl_nhlt_init(struct device *dev);
+void skl_nhlt_free(void *addr);
 struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
                        u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
 
index b05fb1c1a8483e18ea7e5226325563ea82d044c0..794a3499e567c3a907e70b8c1c57aafce6aab207 100644 (file)
@@ -485,6 +485,7 @@ static const struct of_device_id jz4740_of_matches[] = {
        { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, jz4740_of_matches);
 #endif
 
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
index de7563bdc5c28e2c7954a00ca9929e508176d718..e0304d544f26ba45660e94fa98942d2416ddb94a 100644 (file)
@@ -130,6 +130,7 @@ static const struct of_device_id a370db_dt_ids[] = {
        { .compatible = "marvell,a370db-audio" },
        { },
 };
+MODULE_DEVICE_TABLE(of, a370db_dt_ids);
 
 static struct platform_driver a370db_driver = {
        .driver         = {
index 684e8a78bed0640310e0b54e292df725b409fe22..71a1a35047bafd085881efd5369f5275bf9a050f 100644 (file)
@@ -179,21 +179,13 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev)
        }
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
                        __func__, ret);
        return ret;
 }
 
-static int mt8173_max98090_dev_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static const struct of_device_id mt8173_max98090_dt_match[] = {
        { .compatible = "mediatek,mt8173-max98090", },
        { }
@@ -209,7 +201,6 @@ static struct platform_driver mt8173_max98090_driver = {
 #endif
        },
        .probe = mt8173_max98090_dev_probe,
-       .remove = mt8173_max98090_dev_remove,
 };
 
 module_platform_driver(mt8173_max98090_driver);
index 86cf9752f18a343791eaeeff8ca8ab9c2c4a83e8..50ba538eccb3f771da9c08685d4e33aa0cbfa80b 100644 (file)
@@ -246,21 +246,13 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
                        __func__, ret);
        return ret;
 }
 
-static int mt8173_rt5650_rt5676_dev_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
        { .compatible = "mediatek,mt8173-rt5650-rt5676", },
        { }
@@ -276,7 +268,6 @@ static struct platform_driver mt8173_rt5650_rt5676_driver = {
 #endif
        },
        .probe = mt8173_rt5650_rt5676_dev_probe,
-       .remove = mt8173_rt5650_rt5676_dev_remove,
 };
 
 module_platform_driver(mt8173_rt5650_rt5676_driver);
index 6e6fce6a14ba6dc1c2ab14d054df8f5b07b2caea..2b23ffbac6b126cdff2674f68133dea77c40f546 100644 (file)
@@ -142,7 +142,7 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
                        ret);
@@ -154,12 +154,8 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
 
 static int mxs_sgtl5000_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
        mxs_saif_put_mclk(0);
 
-       snd_soc_unregister_card(card);
-
        return 0;
 }
 
index dcb5336b569815b8958e2ecb572710930ca425cb..190f868e78b24af37d8442d378c06aeb8ec6aaf2 100644 (file)
@@ -99,8 +99,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
-       snd_pcm_hw_constraint_minmax(runtime,
-                                    SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 
        n810_ext_control(&rtd->card->dapm);
        return clk_prepare_enable(sys_clkout2);
index 3bebfb1d3a6f9b7ad9a8d20641018d16bf97f886..5e21f08579d804c5f7895a22e87de6cdff8b79ef 100644 (file)
@@ -107,8 +107,7 @@ static int rx51_startup(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_card *card = rtd->card;
 
-       snd_pcm_hw_constraint_minmax(runtime,
-                                    SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
+       snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
        rx51_ext_control(&card->dapm);
 
        return 0;
@@ -297,7 +296,7 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
                dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
                return err;
        }
-       snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
+       snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
 
        err = omap_mcbsp_st_add_controls(rtd, 2);
        if (err < 0) {
index 2b26318bc20097b0c5e369b50f151b7bde511e59..6147e86e9b0fc2f0addc82a2374c7aa3f095bbb8 100644 (file)
@@ -116,26 +116,19 @@ static int brownstone_probe(struct platform_device *pdev)
        int ret;
 
        brownstone.dev = &pdev->dev;
-       ret = snd_soc_register_card(&brownstone);
+       ret = devm_snd_soc_register_card(&pdev->dev, &brownstone);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                                ret);
        return ret;
 }
 
-static int brownstone_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_card(&brownstone);
-       return 0;
-}
-
 static struct platform_driver mmp_driver = {
        .driver         = {
                .name   = "brownstone-audio",
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = brownstone_probe,
-       .remove         = brownstone_remove,
 };
 
 module_platform_driver(mmp_driver);
index 3580d10c9f282312056d6ad3952b6adbcf632ffe..c97dc13d36087628433de516a1b2217df02b492b 100644 (file)
@@ -295,28 +295,19 @@ static int corgi_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
        return ret;
 }
 
-static int corgi_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static struct platform_driver corgi_driver = {
        .driver         = {
                .name   = "corgi-audio",
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = corgi_probe,
-       .remove         = corgi_remove,
 };
 
 module_platform_driver(corgi_driver);
index d72e124a3676bf545be9d0afa49e6180973a00b2..1de876529aa128c39f9fc5000dcb371a778849a3 100644 (file)
@@ -138,7 +138,7 @@ static int e740_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -149,10 +149,7 @@ static int e740_probe(struct platform_device *pdev)
 
 static int e740_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
        gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
-       snd_soc_unregister_card(card);
        return 0;
 }
 
index 48f2d7c2e68c2621f7cce3c6225a166ae8f0920f..b7eb7cd5df7d0814e4c4abe172215d38d2dd5ab1 100644 (file)
@@ -120,7 +120,7 @@ static int e750_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -131,10 +131,7 @@ static int e750_probe(struct platform_device *pdev)
 
 static int e750_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
        gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
-       snd_soc_unregister_card(card);
        return 0;
 }
 
index 45d4bd46fff60d08dbda013b5e7b8f8cefd1851e..41bf71466a7bb619c06de89e81d4e1b6b731c8fb 100644 (file)
@@ -119,7 +119,7 @@ static int e800_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -130,10 +130,7 @@ static int e800_probe(struct platform_device *pdev)
 
 static int e800_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
        gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
-       snd_soc_unregister_card(card);
        return 0;
 }
 
index 9f8be7cd567e48c83218624ddfe2cad538ef28d7..ecbf2873b7ffd8e205ce86fdd7dfa743ebe9435c 100644 (file)
@@ -193,7 +193,7 @@ static int hx4700_audio_probe(struct platform_device *pdev)
                return ret;
 
        snd_soc_card_hx4700.dev = &pdev->dev;
-       ret = snd_soc_register_card(&snd_soc_card_hx4700);
+       ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_hx4700);
        if (ret)
                gpio_free_array(hx4700_audio_gpios,
                                ARRAY_SIZE(hx4700_audio_gpios));
@@ -203,8 +203,6 @@ static int hx4700_audio_probe(struct platform_device *pdev)
 
 static int hx4700_audio_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_card(&snd_soc_card_hx4700);
-
        gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
        gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
 
index 29fabbfd21f1796cd91142c0e99d7addfcc5f924..9d0e40771ef5b01de482aeb9daef67c15f30297f 100644 (file)
@@ -72,28 +72,19 @@ static int imote2_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
        return ret;
 }
 
-static int imote2_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static struct platform_driver imote2_driver = {
        .driver         = {
                .name   = "imote2-audio",
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = imote2_probe,
-       .remove         = imote2_remove,
 };
 
 module_platform_driver(imote2_driver);
index a9615a574546988f6fc8e83fe5a018dc05528cba..29bc60e85e92898e585a57202ad2540f4be61cae 100644 (file)
@@ -181,7 +181,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
                return -ENODEV;
 
        mioa701.dev = &pdev->dev;
-       rc =  snd_soc_register_card(&mioa701);
+       rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);
        if (!rc)
                dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will"
                         "lead to overheating and possible destruction of your device."
@@ -189,17 +189,8 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
        return rc;
 }
 
-static int mioa701_wm9713_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static struct platform_driver mioa701_wm9713_driver = {
        .probe          = mioa701_wm9713_probe,
-       .remove         = mioa701_wm9713_remove,
        .driver         = {
                .name           = "mioa701-wm9713",
                .pm     = &snd_soc_pm_ops,
index c20bbc042425dacb2a478d247f9087b87ba8469c..4e74d9573f032eb77cb79a05f16cfd3da95e4f5b 100644 (file)
@@ -140,22 +140,15 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
 
        palm27x_asoc.dev = &pdev->dev;
 
-       ret = snd_soc_register_card(&palm27x_asoc);
+       ret = devm_snd_soc_register_card(&pdev->dev, &palm27x_asoc);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
        return ret;
 }
 
-static int palm27x_asoc_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_card(&palm27x_asoc);
-       return 0;
-}
-
 static struct platform_driver palm27x_wm9712_driver = {
        .probe          = palm27x_asoc_probe,
-       .remove         = palm27x_asoc_remove,
        .driver         = {
                .name           = "palm27x-asoc",
                .pm     = &snd_soc_pm_ops,
index 80b457ac522acb2c9bdbf1318dfc59bbd36d3789..84d0e2e508088a260b54911bca03236a50046203 100644 (file)
@@ -267,28 +267,19 @@ static int poodle_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
        return ret;
 }
 
-static int poodle_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-       return 0;
-}
-
 static struct platform_driver poodle_driver = {
        .driver         = {
                .name   = "poodle-audio",
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = poodle_probe,
-       .remove         = poodle_remove,
 };
 
 module_platform_driver(poodle_driver);
index 3da485ec1de7fa9d968f1cfd819252258a35cc46..da03fad1b9cda1ad8fb31f4724db0d149948a27e 100644 (file)
@@ -809,6 +809,7 @@ static const struct of_device_id pxa_ssp_of_ids[] = {
        { .compatible = "mrvl,pxa-ssp-dai" },
        {}
 };
+MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
 #endif
 
 static int asoc_ssp_probe(struct platform_device *pdev)
index 9e4b04e0fbd12b452e270214ed2ee7ce09a31b90..f3de615aacd77fcbbc20cc5bf5718b135f931ac8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
 
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
@@ -49,7 +50,11 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_cold_reset,
 };
 
-static unsigned long pxa2xx_ac97_pcm_stereo_in_req = 11;
+static struct pxad_param pxa2xx_ac97_pcm_stereo_in_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 11,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -57,7 +62,11 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
        .filter_data    = &pxa2xx_ac97_pcm_stereo_in_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_stereo_out_req = 12;
+static struct pxad_param pxa2xx_ac97_pcm_stereo_out_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 12,
+};
+
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
        .addr           = __PREG(PCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -65,7 +74,10 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
        .filter_data    = &pxa2xx_ac97_pcm_stereo_out_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_aux_mono_out_req = 10;
+static struct pxad_param pxa2xx_ac97_pcm_aux_mono_out_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 10,
+};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
        .addr           = __PREG(MODR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
@@ -73,7 +85,10 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
        .filter_data    = &pxa2xx_ac97_pcm_aux_mono_out_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_aux_mono_in_req = 9;
+static struct pxad_param pxa2xx_ac97_pcm_aux_mono_in_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 9,
+};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
        .addr           = __PREG(MODR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
@@ -81,7 +96,10 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
        .filter_data    = &pxa2xx_ac97_pcm_aux_mono_in_req,
 };
 
-static unsigned long pxa2xx_ac97_pcm_aux_mic_mono_req = 8;
+static struct pxad_param pxa2xx_ac97_pcm_aux_mic_mono_req = {
+       .prio = PXAD_PRIO_LOWEST,
+       .drcmr = 8,
+};
 static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
        .addr           = __PREG(MCDR),
        .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
@@ -89,9 +107,8 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
        .filter_data    = &pxa2xx_ac97_pcm_aux_mic_mono_req,
 };
 
-static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *cpu_dai)
+static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *cpu_dai)
 {
        struct snd_dmaengine_dai_dma_data *dma_data;
 
@@ -105,9 +122,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
-                                    struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *cpu_dai)
+static int pxa2xx_ac97_aux_startup(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *cpu_dai)
 {
        struct snd_dmaengine_dai_dma_data *dma_data;
 
@@ -121,9 +137,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
-                                    struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *cpu_dai)
+static int pxa2xx_ac97_mic_startup(struct snd_pcm_substream *substream,
+                                  struct snd_soc_dai *cpu_dai)
 {
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
@@ -139,15 +154,15 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_48000)
 
 static const struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
-       .hw_params      = pxa2xx_ac97_hw_params,
+       .startup        = pxa2xx_ac97_hifi_startup,
 };
 
 static const struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
-       .hw_params      = pxa2xx_ac97_hw_aux_params,
+       .startup        = pxa2xx_ac97_aux_startup,
 };
 
 static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
-       .hw_params      = pxa2xx_ac97_hw_mic_params,
+       .startup        = pxa2xx_ac97_mic_startup,
 };
 
 /*
index 6b4e400369107ccfac6513d28953b38e7805accd..0389cf7b4b1ea57169bb33ab8208937c63ef3cc2 100644 (file)
@@ -319,6 +319,9 @@ static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
        /* Along with FIFO servicing */
        SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
 
+       snd_soc_dai_init_dma_data(dai, &pxa2xx_i2s_pcm_stereo_out,
+               &pxa2xx_i2s_pcm_stereo_in);
+
        return 0;
 }
 
index 831ee37d2e3e714941855ebdef31bb3eaf15d26a..9f390398d518046ebd336a5834ef8207bd283e36 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/dmaengine.h>
 #include <linux/of.h>
 
-#include <mach/dma.h>
-
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct pxa2xx_runtime_data *prtd = runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_dmaengine_dai_dma_data *dma;
-       int ret;
 
        dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
@@ -40,40 +35,13 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        if (!dma)
                return 0;
 
-       /* this may get called several times by oss emulation
-        * with different params */
-       if (prtd->params == NULL) {
-               prtd->params = dma;
-               ret = pxa_request_dma("name", DMA_PRIO_LOW,
-                             pxa2xx_pcm_dma_irq, substream);
-               if (ret < 0)
-                       return ret;
-               prtd->dma_ch = ret;
-       } else if (prtd->params != dma) {
-               pxa_free_dma(prtd->dma_ch);
-               prtd->params = dma;
-               ret = pxa_request_dma("name", DMA_PRIO_LOW,
-                             pxa2xx_pcm_dma_irq, substream);
-               if (ret < 0)
-                       return ret;
-               prtd->dma_ch = ret;
-       }
-
        return __pxa2xx_pcm_hw_params(substream, params);
 }
 
 static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
-
        __pxa2xx_pcm_hw_free(substream);
 
-       if (prtd->dma_ch >= 0) {
-               pxa_free_dma(prtd->dma_ch);
-               prtd->dma_ch = -1;
-               prtd->params = NULL;
-       }
-
        return 0;
 }
 
@@ -132,6 +100,7 @@ static const struct of_device_id snd_soc_pxa_audio_match[] = {
        { .compatible   = "mrvl,pxa-pcm-audio" },
        { }
 };
+MODULE_DEVICE_TABLE(of, snd_soc_pxa_audio_match);
 #endif
 
 static struct platform_driver pxa_pcm_driver = {
index 461123ad5ff2d4c56e21a97a14e27f8ce7d841c4..b00222620fd01be5cf00d4118d44f18832ad3bdc 100644 (file)
@@ -305,7 +305,7 @@ static int spitz_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -322,9 +322,6 @@ err1:
 
 static int spitz_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
        gpio_free(spitz_mic_gpio);
        return 0;
 }
index f59f566551ef72ad4e0b5c4bb369d1c8b8de7ec0..49518dd642aa18ffd3f0004fe2f425210e820b54 100644 (file)
@@ -233,7 +233,7 @@ static int tosa_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -244,10 +244,7 @@ static int tosa_probe(struct platform_device *pdev)
 
 static int tosa_remove(struct platform_device *pdev)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
        gpio_free(TOSA_GPIO_L_MUTE);
-       snd_soc_unregister_card(card);
        return 0;
 }
 
index 1753c7d9e760e4bfa14e5b5ed8844b530e7413cf..65c20f779177589bcb7eb0ce8d61a2196806eb69 100644 (file)
@@ -128,7 +128,7 @@ static int ttc_dkb_probe(struct platform_device *pdev)
 
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
@@ -136,22 +136,12 @@ static int ttc_dkb_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int ttc_dkb_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
-}
-
 static struct platform_driver ttc_dkb_driver = {
        .driver         = {
                .name   = "ttc-dkb-audio",
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = ttc_dkb_probe,
-       .remove         = ttc_dkb_remove,
 };
 
 module_platform_driver(ttc_dkb_driver);
index 97bc2023f08aa81fff0b1524b6fb0f34e992c23b..e5101e0d2d372262f8ecf7d0498240cba971b86f 100644 (file)
@@ -438,7 +438,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
                if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
                        dev_err(&pdev->dev,
                                "%s() error getting mi2s-bit-clk: %ld\n",
-                               __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+                               __func__,
+                               PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
                        return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
                }
        }
index 58bae8e2cf5ff7b9d1922feceaa0ac7347483561..f1e0c703e0d2f105226c2becffafc852f1927879 100644 (file)
@@ -15,9 +15,17 @@ config SND_SOC_ROCKCHIP_I2S
          Rockchip I2S device. The device supports upto maximum of
          8 channels each for play and record.
 
+config SND_SOC_ROCKCHIP_SPDIF
+       tristate "Rockchip SPDIF Device Driver"
+       depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M if you want to add support for SPDIF driver for
+         Rockchip SPDIF transceiver device.
+
 config SND_SOC_ROCKCHIP_MAX98090
        tristate "ASoC support for Rockchip boards using a MAX98090 codec"
-       depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+       depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP
        select SND_SOC_ROCKCHIP_I2S
        select SND_SOC_MAX98090
        select SND_SOC_TS3A227E
@@ -27,7 +35,7 @@ config SND_SOC_ROCKCHIP_MAX98090
 
 config SND_SOC_ROCKCHIP_RT5645
        tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec"
-       depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+       depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP
        select SND_SOC_ROCKCHIP_I2S
        select SND_SOC_RT5645
        help
index 1bc1dc3c729a40ce715903346a8c409c319b4fb7..c0bf560125f3d8d4fc4131fd65cbb277be8bb8ac 100644 (file)
@@ -1,7 +1,9 @@
 # ROCKCHIP Platform Support
-snd-soc-i2s-objs := rockchip_i2s.o
+snd-soc-rockchip-i2s-objs := rockchip_i2s.o
+snd-soc-rockchip-spdif-objs := rockchip_spdif.o
 
-obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
index b93610212e3df75354e34d89dcb1999930a1705a..58ee64594f075efb7327d1480113f1401e97f248 100644 (file)
@@ -226,6 +226,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
        struct rk_i2s_dev *i2s = to_info(dai);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        unsigned int val = 0;
 
        switch (params_format(params)) {
@@ -245,13 +246,46 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
-       regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
+       switch (params_channels(params)) {
+       case 8:
+               val |= I2S_CHN_8;
+               break;
+       case 6:
+               val |= I2S_CHN_6;
+               break;
+       case 4:
+               val |= I2S_CHN_4;
+               break;
+       case 2:
+               val |= I2S_CHN_2;
+               break;
+       default:
+               dev_err(i2s->dev, "invalid channel: %d\n",
+                       params_channels(params));
+               return -EINVAL;
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               regmap_update_bits(i2s->regmap, I2S_RXCR,
+                                  I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK,
+                                  val);
+       else
+               regmap_update_bits(i2s->regmap, I2S_TXCR,
+                                  I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,
+                                  val);
+
        regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
                           I2S_DMACR_TDL(16));
        regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
                           I2S_DMACR_RDL(16));
 
+       val = I2S_CKR_TRCM_TXRX;
+       if (dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)
+               val = I2S_CKR_TRCM_TXSHARE;
+
+       regmap_update_bits(i2s->regmap, I2S_CKR,
+                          I2S_CKR_TRCM_MASK,
+                          val);
        return 0;
 }
 
@@ -415,10 +449,12 @@ static const struct regmap_config rockchip_i2s_regmap_config = {
 
 static int rockchip_i2s_probe(struct platform_device *pdev)
 {
+       struct device_node *node = pdev->dev.of_node;
        struct rk_i2s_dev *i2s;
        struct resource *res;
        void __iomem *regs;
        int ret;
+       int val;
 
        i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
        if (!i2s) {
@@ -475,6 +511,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
+       /* refine capture channels */
+       if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
+               if (val >= 2 && val <= 8)
+                       rockchip_i2s_dai.capture.channels_max = val;
+               else
+                       rockchip_i2s_dai.capture.channels_max = 2;
+       }
+
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &rockchip_i2s_component,
                                              &rockchip_i2s_dai, 1);
index 93f456f518a97dc9a048350093acae715852e10a..dc6e2c74d08818bf68d333f2ca4d811eb914b7ed 100644 (file)
@@ -49,6 +49,9 @@
  * RXCR
  * receive operation control register
 */
+#define I2S_RXCR_CSR_SHIFT     15
+#define I2S_RXCR_CSR(x)                (x << I2S_RXCR_CSR_SHIFT)
+#define I2S_RXCR_CSR_MASK      (3 << I2S_RXCR_CSR_SHIFT)
 #define I2S_RXCR_HWT           BIT(14)
 #define I2S_RXCR_SJM_SHIFT     12
 #define I2S_RXCR_SJM_R         (0 << I2S_RXCR_SJM_SHIFT)
  * CKR
  * clock generation register
 */
+#define I2S_CKR_TRCM_SHIFT     28
+#define I2S_CKR_TRCM(x)        (x << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_TXRX      (0 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_TXSHARE   (1 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_RXSHARE   (2 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_MASK      (3 << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_MSS_SHIFT      27
 #define I2S_CKR_MSS_MASTER     (0 << I2S_CKR_MSS_SHIFT)
 #define I2S_CKR_MSS_SLAVE      (1 << I2S_CKR_MSS_SHIFT)
@@ -207,6 +216,13 @@ enum {
        ROCKCHIP_DIV_BCLK,
 };
 
+/* channel select */
+#define I2S_CSR_SHIFT  15
+#define I2S_CHN_2      (0 << I2S_CSR_SHIFT)
+#define I2S_CHN_4      (1 << I2S_CSR_SHIFT)
+#define I2S_CHN_6      (2 << I2S_CSR_SHIFT)
+#define I2S_CHN_8      (3 << I2S_CSR_SHIFT)
+
 /* I2S REGS */
 #define I2S_TXCR       (0x0000)
 #define I2S_RXCR       (0x0004)
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
new file mode 100644 (file)
index 0000000..a38a302
--- /dev/null
@@ -0,0 +1,405 @@
+/* sound/soc/rockchip/rk_spdif.c
+ *
+ * ALSA SoC Audio Layer - Rockchip I2S Controller driver
+ *
+ * Copyright (c) 2014 Rockchip Electronics Co. Ltd.
+ * Author: Jianqun <jay.xu@rock-chips.com>
+ * Copyright (c) 2015 Collabora Ltd.
+ * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "rockchip_spdif.h"
+
+enum rk_spdif_type {
+       RK_SPDIF_RK3066,
+       RK_SPDIF_RK3188,
+       RK_SPDIF_RK3288,
+};
+
+#define RK3288_GRF_SOC_CON2 0x24c
+
+struct rk_spdif_dev {
+       struct device *dev;
+
+       struct clk *mclk;
+       struct clk *hclk;
+
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
+
+       struct regmap *regmap;
+};
+
+static const struct of_device_id rk_spdif_match[] = {
+       { .compatible = "rockchip,rk3066-spdif",
+         .data = (void *) RK_SPDIF_RK3066 },
+       { .compatible = "rockchip,rk3188-spdif",
+         .data = (void *) RK_SPDIF_RK3188 },
+       { .compatible = "rockchip,rk3288-spdif",
+         .data = (void *) RK_SPDIF_RK3288 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rk_spdif_match);
+
+static int rk_spdif_runtime_suspend(struct device *dev)
+{
+       struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(spdif->mclk);
+       clk_disable_unprepare(spdif->hclk);
+
+       return 0;
+}
+
+static int rk_spdif_runtime_resume(struct device *dev)
+{
+       struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(spdif->mclk);
+       if (ret) {
+               dev_err(spdif->dev, "mclk clock enable failed %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(spdif->hclk);
+       if (ret) {
+               dev_err(spdif->dev, "hclk clock enable failed %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rk_spdif_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
+       unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE;
+       int srate, mclk;
+       int ret;
+
+       srate = params_rate(params);
+       switch (srate) {
+       case 32000:
+       case 48000:
+       case 96000:
+               mclk = 96000 * 128; /* 12288000 hz */
+               break;
+       case 44100:
+               mclk = 44100 * 256; /* 11289600 hz */
+               break;
+       case 192000:
+               mclk = 192000 * 128; /* 24576000 hz */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               val |= SPDIF_CFGR_VDW_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val |= SPDIF_CFGR_VDW_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val |= SPDIF_CFGR_VDW_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Set clock and calculate divider */
+       ret = clk_set_rate(spdif->mclk, mclk);
+       if (ret != 0) {
+               dev_err(spdif->dev, "Failed to set module clock rate: %d\n",
+                       ret);
+               return ret;
+       }
+
+       val |= SPDIF_CFGR_CLK_DIV(mclk/(srate * 256));
+       ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR,
+               SPDIF_CFGR_CLK_DIV_MASK | SPDIF_CFGR_HALFWORD_ENABLE |
+               SDPIF_CFGR_VDW_MASK,
+               val);
+
+       return ret;
+}
+
+static int rk_spdif_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
+                                  SPDIF_DMACR_TDE_ENABLE,
+                                  SPDIF_DMACR_TDE_ENABLE);
+
+               if (ret != 0)
+                       return ret;
+
+               ret = regmap_update_bits(spdif->regmap, SPDIF_XFER,
+                                  SPDIF_XFER_TXS_START,
+                                  SPDIF_XFER_TXS_START);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
+                                  SPDIF_DMACR_TDE_ENABLE,
+                                  SPDIF_DMACR_TDE_DISABLE);
+
+               if (ret != 0)
+                       return ret;
+
+               ret = regmap_update_bits(spdif->regmap, SPDIF_XFER,
+                                  SPDIF_XFER_TXS_START,
+                                  SPDIF_XFER_TXS_STOP);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int rk_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+       struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &spdif->playback_dma_data;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops rk_spdif_dai_ops = {
+       .hw_params = rk_spdif_hw_params,
+       .trigger = rk_spdif_trigger,
+};
+
+static struct snd_soc_dai_driver rk_spdif_dai = {
+       .probe = rk_spdif_dai_probe,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = (SNDRV_PCM_RATE_32000 |
+                         SNDRV_PCM_RATE_44100 |
+                         SNDRV_PCM_RATE_48000 |
+                         SNDRV_PCM_RATE_96000 |
+                         SNDRV_PCM_RATE_192000),
+               .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+                           SNDRV_PCM_FMTBIT_S20_3LE |
+                           SNDRV_PCM_FMTBIT_S24_LE),
+       },
+       .ops = &rk_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver rk_spdif_component = {
+       .name = "rockchip-spdif",
+};
+
+static bool rk_spdif_wr_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SPDIF_CFGR:
+       case SPDIF_DMACR:
+       case SPDIF_INTCR:
+       case SPDIF_XFER:
+       case SPDIF_SMPDR:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rk_spdif_rd_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SPDIF_CFGR:
+       case SPDIF_SDBLR:
+       case SPDIF_INTCR:
+       case SPDIF_INTSR:
+       case SPDIF_XFER:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rk_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SPDIF_INTSR:
+       case SPDIF_SDBLR:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config rk_spdif_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = SPDIF_SMPDR,
+       .writeable_reg = rk_spdif_wr_reg,
+       .readable_reg = rk_spdif_rd_reg,
+       .volatile_reg = rk_spdif_volatile_reg,
+       .cache_type = REGCACHE_FLAT,
+};
+
+static int rk_spdif_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct rk_spdif_dev *spdif;
+       const struct of_device_id *match;
+       struct resource *res;
+       void __iomem *regs;
+       int ret;
+
+       match = of_match_node(rk_spdif_match, np);
+       if ((int) match->data == RK_SPDIF_RK3288) {
+               struct regmap *grf;
+
+               grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+               if (IS_ERR(grf)) {
+                       dev_err(&pdev->dev,
+                               "rockchip_spdif missing 'rockchip,grf' \n");
+                       return PTR_ERR(grf);
+               }
+
+               /* Select the 8 channel SPDIF solution on RK3288 as
+                * the 2 channel one does not appear to work
+                */
+               regmap_write(grf, RK3288_GRF_SOC_CON2, BIT(1) << 16);
+       }
+
+       spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+       if (!spdif)
+               return -ENOMEM;
+
+       spdif->hclk = devm_clk_get(&pdev->dev, "hclk");
+       if (IS_ERR(spdif->hclk)) {
+               dev_err(&pdev->dev, "Can't retrieve rk_spdif bus clock\n");
+               return PTR_ERR(spdif->hclk);
+       }
+       ret = clk_prepare_enable(spdif->hclk);
+       if (ret) {
+               dev_err(spdif->dev, "hclock enable failed %d\n", ret);
+               return ret;
+       }
+
+       spdif->mclk = devm_clk_get(&pdev->dev, "mclk");
+       if (IS_ERR(spdif->mclk)) {
+               dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n");
+               return PTR_ERR(spdif->mclk);
+       }
+
+       ret = clk_prepare_enable(spdif->mclk);
+       if (ret) {
+               dev_err(spdif->dev, "clock enable failed %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs,
+                                                 &rk_spdif_regmap_config);
+       if (IS_ERR(spdif->regmap)) {
+               dev_err(&pdev->dev,
+                       "Failed to initialise managed register map\n");
+               return PTR_ERR(spdif->regmap);
+       }
+
+       spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR;
+       spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       spdif->playback_dma_data.maxburst = 4;
+
+       spdif->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_request_idle(&pdev->dev);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &rk_spdif_component,
+                                             &rk_spdif_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI\n");
+               goto err_pm_runtime;
+       }
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM\n");
+               goto err_pm_runtime;
+       }
+
+       return 0;
+
+err_pm_runtime:
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static int rk_spdif_remove(struct platform_device *pdev)
+{
+       struct rk_spdif_dev *spdif = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               rk_spdif_runtime_suspend(&pdev->dev);
+
+       clk_disable_unprepare(spdif->mclk);
+       clk_disable_unprepare(spdif->hclk);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rk_spdif_pm_ops = {
+       SET_RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume,
+                          NULL)
+};
+
+static struct platform_driver rk_spdif_driver = {
+       .probe = rk_spdif_probe,
+       .remove = rk_spdif_remove,
+       .driver = {
+               .name = "rockchip-spdif",
+               .of_match_table = of_match_ptr(rk_spdif_match),
+               .pm = &rk_spdif_pm_ops,
+       },
+};
+module_platform_driver(rk_spdif_driver);
+
+MODULE_ALIAS("platform:rockchip-spdif");
+MODULE_DESCRIPTION("ROCKCHIP SPDIF transceiver Interface");
+MODULE_AUTHOR("Sjoerd Simons <sjoerd.simons@collabora.co.uk>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/rockchip/rockchip_spdif.h b/sound/soc/rockchip/rockchip_spdif.h
new file mode 100644 (file)
index 0000000..07f86a2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ALSA SoC Audio Layer - Rockchip SPDIF transceiver driver
+ *
+ * Copyright (c) 2015 Collabora Ltd.
+ * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ROCKCHIP_SPDIF_H
+#define _ROCKCHIP_SPDIF_H
+
+/*
+ * CFGR
+ * transfer configuration register
+*/
+#define SPDIF_CFGR_CLK_DIV_SHIFT       (16)
+#define SPDIF_CFGR_CLK_DIV_MASK                (0xff << SPDIF_CFGR_CLK_DIV_SHIFT)
+#define SPDIF_CFGR_CLK_DIV(x)          (x << SPDIF_CFGR_CLK_DIV_SHIFT)
+
+#define SPDIF_CFGR_HALFWORD_SHIFT      2
+#define SPDIF_CFGR_HALFWORD_DISABLE    (0 << SPDIF_CFGR_HALFWORD_SHIFT)
+#define SPDIF_CFGR_HALFWORD_ENABLE     (1 << SPDIF_CFGR_HALFWORD_SHIFT)
+
+#define SPDIF_CFGR_VDW_SHIFT   0
+#define SPDIF_CFGR_VDW(x)      (x << SPDIF_CFGR_VDW_SHIFT)
+#define SDPIF_CFGR_VDW_MASK    (0xf << SPDIF_CFGR_VDW_SHIFT)
+
+#define SPDIF_CFGR_VDW_16      SPDIF_CFGR_VDW(0x00)
+#define SPDIF_CFGR_VDW_20      SPDIF_CFGR_VDW(0x01)
+#define SPDIF_CFGR_VDW_24      SPDIF_CFGR_VDW(0x10)
+
+/*
+ * DMACR
+ * DMA control register
+*/
+#define SPDIF_DMACR_TDE_SHIFT  5
+#define SPDIF_DMACR_TDE_DISABLE        (0 << SPDIF_DMACR_TDE_SHIFT)
+#define SPDIF_DMACR_TDE_ENABLE (1 << SPDIF_DMACR_TDE_SHIFT)
+
+#define SPDIF_DMACR_TDL_SHIFT  0
+#define SPDIF_DMACR_TDL(x)     ((x) << SPDIF_DMACR_TDL_SHIFT)
+#define SPDIF_DMACR_TDL_MASK   (0x1f << SDPIF_DMACR_TDL_SHIFT)
+
+/*
+ * XFER
+ * Transfer control register
+*/
+#define SPDIF_XFER_TXS_SHIFT   0
+#define SPDIF_XFER_TXS_STOP    (0 << SPDIF_XFER_TXS_SHIFT)
+#define SPDIF_XFER_TXS_START   (1 << SPDIF_XFER_TXS_SHIFT)
+
+#define SPDIF_CFGR     (0x0000)
+#define SPDIF_SDBLR    (0x0004)
+#define SPDIF_DMACR    (0x0008)
+#define SPDIF_INTCR    (0x000c)
+#define SPDIF_INTSR    (0x0010)
+#define SPDIF_XFER     (0x0018)
+#define SPDIF_SMPDR    (0x0020)
+
+#endif /* _ROCKCHIP_SPDIF_H */
index c72e9fb26658ce17036761164e6fd9e083618841..5f5825faeb2a4331177595eaabcd0600b9d2476e 100644 (file)
 #include <mach/gpio-samsung.h>
 #include "s3c24xx-i2s.h"
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        11025,
        22050,
        44100,
 };
 
-static struct snd_pcm_hw_constraint_list hw_rates = {
+static const struct snd_pcm_hw_constraint_list hw_rates = {
        .count = ARRAY_SIZE(rates),
        .list = rates,
-       .mask = 0,
 };
 
 static struct snd_soc_jack hp_jack;
index 35e37c457f1fd311ee982169010df6507939924d..fa096abe9e75689b58e46bb818810838a78c6080 100644 (file)
@@ -38,16 +38,15 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
 static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
                                struct snd_kcontrol *kcontrol, int event);
 
-static unsigned int rates[] = {
+static const unsigned int rates[] = {
        16000,
        44100,
        48000,
 };
 
-static struct snd_pcm_hw_constraint_list hw_rates = {
+static const struct snd_pcm_hw_constraint_list hw_rates = {
        .count = ARRAY_SIZE(rates),
        .list = rates,
-       .mask = 0,
 };
 
 static struct snd_soc_jack hp_jack;
index 07114b0b0dc12bcf23e0a25fb342ad3df23b2464..206d1edab07c1f8a8c91c1b69363b3bc057d38ec 100644 (file)
@@ -37,10 +37,11 @@ config SND_SOC_SH4_SIU
 config SND_SOC_RCAR
        tristate "R-Car series SRU/SCU/SSIU/SSI support"
        depends on DMA_OF
+       depends on COMMON_CLK
        select SND_SIMPLE_CARD
        select REGMAP_MMIO
        help
-         This option enables R-Car SUR/SCU/SSIU/SSI sound support
+         This option enables R-Car SRU/SCU/SSIU/SSI sound support
 
 config SND_SOC_RSRC_CARD
        tristate "Renesas Sampling Rate Convert Sound Card"
index fefc881dbac24acf8e190703973712d8ccc8f22c..2a5b3a293cd243db3d4325b5f6a8e2b4e7041611 100644 (file)
@@ -7,7 +7,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
-#include <linux/sh_clk.h>
+#include <linux/clk-provider.h>
 #include "rsnd.h"
 
 #define CLKA   0
 #define CLKI   3
 #define CLKMAX 4
 
+#define CLKOUT 0
+#define CLKOUT1        1
+#define CLKOUT2        2
+#define CLKOUT3        3
+#define CLKOUTMAX 4
+
+#define BRRx_MASK(x) (0x3FF & x)
+
+static struct rsnd_mod_ops adg_ops = {
+       .name = "adg",
+};
+
 struct rsnd_adg {
        struct clk *clk[CLKMAX];
+       struct clk *clkout[CLKOUTMAX];
+       struct clk_onecell_data onecell;
+       struct rsnd_mod mod;
 
-       int rbga_rate_for_441khz_div_6; /* RBGA */
-       int rbgb_rate_for_48khz_div_6;  /* RBGB */
-       u32 ckr;
+       int rbga_rate_for_441khz; /* RBGA */
+       int rbgb_rate_for_48khz;  /* RBGB */
 };
 
 #define for_each_rsnd_clk(pos, adg, i)         \
@@ -29,17 +43,36 @@ struct rsnd_adg {
             (i < CLKMAX) &&                    \
             ((pos) = adg->clk[i]);             \
             i++)
+#define for_each_rsnd_clkout(pos, adg, i)      \
+       for (i = 0;                             \
+            (i < CLKOUTMAX) &&                 \
+            ((pos) = adg->clkout[i]);  \
+            i++)
 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 
+static u32 rsnd_adg_calculate_rbgx(unsigned long div)
+{
+       int i, ratio;
+
+       if (!div)
+               return 0;
+
+       for (i = 3; i >= 0; i--) {
+               ratio = 2 << (i * 2);
+               if (0 == (div % ratio))
+                       return (u32)((i << 8) | ((div / ratio) - 1));
+       }
+
+       return ~0;
+}
 
 static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 {
        struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        int id = rsnd_mod_id(mod);
        int ws = id;
 
-       if (rsnd_ssi_is_pin_sharing(rsnd_ssi_mod_get(priv, id))) {
+       if (rsnd_ssi_is_pin_sharing(io)) {
                switch (id) {
                case 1:
                case 2:
@@ -60,6 +93,9 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io)
 {
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        int id = rsnd_mod_id(mod);
        int shift = (id % 2) ? 16 : 0;
        u32 mask, val;
@@ -69,21 +105,26 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
        val  = val      << shift;
        mask = 0xffff   << shift;
 
-       rsnd_mod_bset(mod, CMDOUT_TIMSEL, mask, val);
+       rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
 
        return 0;
 }
 
-static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod,
                                        struct rsnd_dai_stream *io,
                                        u32 timsel)
 {
+       struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        int is_play = rsnd_io_is_play(io);
-       int id = rsnd_mod_id(mod);
+       int id = rsnd_mod_id(src_mod);
        int shift = (id % 2) ? 16 : 0;
        u32 mask, ws;
        u32 in, out;
 
+       rsnd_mod_confirm_src(src_mod);
+
        ws = rsnd_adg_ssi_ws_timing_gen2(io);
 
        in  = (is_play) ? timsel : ws;
@@ -95,37 +136,38 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
 
        switch (id / 2) {
        case 0:
-               rsnd_mod_bset(mod, SRCIN_TIMSEL0,  mask, in);
-               rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out);
+               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0,  mask, in);
+               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
                break;
        case 1:
-               rsnd_mod_bset(mod, SRCIN_TIMSEL1,  mask, in);
-               rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out);
+               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1,  mask, in);
+               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
                break;
        case 2:
-               rsnd_mod_bset(mod, SRCIN_TIMSEL2,  mask, in);
-               rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out);
+               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2,  mask, in);
+               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
                break;
        case 3:
-               rsnd_mod_bset(mod, SRCIN_TIMSEL3,  mask, in);
-               rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out);
+               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3,  mask, in);
+               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
                break;
        case 4:
-               rsnd_mod_bset(mod, SRCIN_TIMSEL4,  mask, in);
-               rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out);
+               rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4,  mask, in);
+               rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
                break;
        }
 
        return 0;
 }
 
-int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *src_mod,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
                                  unsigned int dst_rate)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        struct device *dev = rsnd_priv_to_dev(priv);
        int idx, sel, div, step, ret;
        u32 val, en;
@@ -134,10 +176,12 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
                clk_get_rate(adg->clk[CLKA]),   /* 0000: CLKA */
                clk_get_rate(adg->clk[CLKB]),   /* 0001: CLKB */
                clk_get_rate(adg->clk[CLKC]),   /* 0010: CLKC */
-               adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */
-               adg->rbgb_rate_for_48khz_div_6, /* 0100: RBGB */
+               adg->rbga_rate_for_441khz,      /* 0011: RBGA */
+               adg->rbgb_rate_for_48khz,       /* 0100: RBGB */
        };
 
+       rsnd_mod_confirm_src(src_mod);
+
        min = ~0;
        val = 0;
        en = 0;
@@ -175,25 +219,27 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
                return -EIO;
        }
 
-       ret = rsnd_adg_set_src_timsel_gen2(mod, io, val);
+       ret = rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
        if (ret < 0) {
                dev_err(dev, "timsel error\n");
                return ret;
        }
 
-       rsnd_mod_bset(mod, DIV_EN, en, en);
+       rsnd_mod_bset(adg_mod, DIV_EN, en, en);
 
        dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
 
        return 0;
 }
 
-int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
                                     struct rsnd_dai_stream *io)
 {
        u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
 
-       return rsnd_adg_set_src_timsel_gen2(mod, io, val);
+       rsnd_mod_confirm_src(src_mod);
+
+       return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
 }
 
 int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
@@ -202,6 +248,7 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
                                  unsigned int dst_rate)
 {
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        struct device *dev = rsnd_priv_to_dev(priv);
        int idx, sel, div, shift;
        u32 mask, val;
@@ -211,8 +258,8 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
                clk_get_rate(adg->clk[CLKB]),   /* 001: CLKB */
                clk_get_rate(adg->clk[CLKC]),   /* 010: CLKC */
                0,                              /* 011: MLBCLK (not used) */
-               adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */
-               adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */
+               adg->rbga_rate_for_441khz,      /* 100: RBGA */
+               adg->rbgb_rate_for_48khz,       /* 101: RBGB */
        };
 
        /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
@@ -238,13 +285,13 @@ find_rate:
 
        switch (id / 4) {
        case 0:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
                break;
        case 1:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
                break;
        case 2:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
                break;
        }
 
@@ -257,12 +304,17 @@ find_rate:
        return 0;
 }
 
-static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
+static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
 {
-       int id = rsnd_mod_id(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       int id = rsnd_mod_id(ssi_mod);
        int shift = (id % 4) * 8;
        u32 mask = 0xFF << shift;
 
+       rsnd_mod_confirm_ssi(ssi_mod);
+
        val = val << shift;
 
        /*
@@ -274,13 +326,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
 
        switch (id / 4) {
        case 0:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
                break;
        case 1:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
                break;
        case 2:
-               rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val);
+               rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
                break;
        }
 }
@@ -326,14 +378,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
        }
 
        /*
-        * find 1/6 clock from BRGA/BRGB
+        * find divided clock from BRGA/BRGB
         */
-       if (rate == adg->rbga_rate_for_441khz_div_6) {
+       if (rate  == adg->rbga_rate_for_441khz) {
                data = 0x10;
                goto found_clock;
        }
 
-       if (rate == adg->rbgb_rate_for_48khz_div_6) {
+       if (rate == adg->rbgb_rate_for_48khz) {
                data = 0x20;
                goto found_clock;
        }
@@ -342,29 +394,60 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
 
 found_clock:
 
-       /* see rsnd_adg_ssi_clk_init() */
-       rsnd_mod_bset(mod, SSICKR, 0x00FF0000, adg->ckr);
-       rsnd_mod_write(mod, BRRA,  0x00000002); /* 1/6 */
-       rsnd_mod_write(mod, BRRB,  0x00000002); /* 1/6 */
-
        /*
         * This "mod" = "ssi" here.
         * we can get "ssi id" from mod
         */
        rsnd_adg_set_ssi_clk(mod, data);
 
-       dev_dbg(dev, "ADG: ssi%d selects clk%d = %d",
-               rsnd_mod_id(mod), i, rate);
+       dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               data, rate);
 
        return 0;
 }
 
-static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
+static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
+                              struct rsnd_adg *adg)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       static const char * const clk_name[] = {
+               [CLKA]  = "clk_a",
+               [CLKB]  = "clk_b",
+               [CLKC]  = "clk_c",
+               [CLKI]  = "clk_i",
+       };
+       int i;
+
+       for (i = 0; i < CLKMAX; i++) {
+               clk = devm_clk_get(dev, clk_name[i]);
+               adg->clk[i] = IS_ERR(clk) ? NULL : clk;
+       }
+
+       for_each_rsnd_clk(clk, adg, i)
+               dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+}
+
+static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
+                               struct rsnd_adg *adg)
 {
        struct clk *clk;
-       unsigned long rate;
-       u32 ckr;
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+       u32 ckr, rbgx, rbga, rbgb;
+       u32 rate, req_rate, div;
+       uint32_t count = 0;
+       unsigned long req_48kHz_rate, req_441kHz_rate;
        int i;
+       const char *parent_clk_name = NULL;
+       static const char * const clkout_name[] = {
+               [CLKOUT]  = "audio_clkout",
+               [CLKOUT1] = "audio_clkout1",
+               [CLKOUT2] = "audio_clkout2",
+               [CLKOUT3] = "audio_clkout3",
+       };
        int brg_table[] = {
                [CLKA] = 0x0,
                [CLKB] = 0x1,
@@ -372,19 +455,34 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
                [CLKI] = 0x2,
        };
 
+       of_property_read_u32(np, "#clock-cells", &count);
+
+       /*
+        * ADG supports BRRA/BRRB output only
+        * this means all clkout0/1/2/3 will be same rate
+        */
+       of_property_read_u32(np, "clock-frequency", &req_rate);
+       req_48kHz_rate = 0;
+       req_441kHz_rate = 0;
+       if (0 == (req_rate % 44100))
+               req_441kHz_rate = req_rate;
+       if (0 == (req_rate % 48000))
+               req_48kHz_rate = req_rate;
+
        /*
         * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
         * have 44.1kHz or 48kHz base clocks for now.
         *
         * SSI itself can divide parent clock by 1/1 - 1/16
-        * So,  BRGA outputs 44.1kHz base parent clock 1/32,
-        * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
         * see
         *      rsnd_adg_ssi_clk_try_start()
+        *      rsnd_ssi_master_clk_start()
         */
        ckr = 0;
-       adg->rbga_rate_for_441khz_div_6 = 0;
-       adg->rbgb_rate_for_48khz_div_6  = 0;
+       rbga = 2; /* default 1/6 */
+       rbgb = 2; /* default 1/6 */
+       adg->rbga_rate_for_441khz       = 0;
+       adg->rbgb_rate_for_48khz        = 0;
        for_each_rsnd_clk(clk, adg, i) {
                rate = clk_get_rate(clk);
 
@@ -392,19 +490,86 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
                        continue;
 
                /* RBGA */
-               if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) {
-                       adg->rbga_rate_for_441khz_div_6 = rate / 6;
-                       ckr |= brg_table[i] << 20;
+               if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
+                       div = 6;
+                       if (req_441kHz_rate)
+                               div = rate / req_441kHz_rate;
+                       rbgx = rsnd_adg_calculate_rbgx(div);
+                       if (BRRx_MASK(rbgx) == rbgx) {
+                               rbga = rbgx;
+                               adg->rbga_rate_for_441khz = rate / div;
+                               ckr |= brg_table[i] << 20;
+                               if (req_441kHz_rate)
+                                       parent_clk_name = __clk_get_name(clk);
+                       }
                }
 
                /* RBGB */
-               if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) {
-                       adg->rbgb_rate_for_48khz_div_6 = rate / 6;
-                       ckr |= brg_table[i] << 16;
+               if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
+                       div = 6;
+                       if (req_48kHz_rate)
+                               div = rate / req_48kHz_rate;
+                       rbgx = rsnd_adg_calculate_rbgx(div);
+                       if (BRRx_MASK(rbgx) == rbgx) {
+                               rbgb = rbgx;
+                               adg->rbgb_rate_for_48khz = rate / div;
+                               ckr |= brg_table[i] << 16;
+                               if (req_48kHz_rate) {
+                                       parent_clk_name = __clk_get_name(clk);
+                                       ckr |= 0x80000000;
+                               }
+                       }
                }
        }
 
-       adg->ckr = ckr;
+       /*
+        * ADG supports BRRA/BRRB output only.
+        * this means all clkout0/1/2/3 will be * same rate
+        */
+
+       /*
+        * for clkout
+        */
+       if (!count) {
+               clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
+                                             parent_clk_name,
+                                             (parent_clk_name) ?
+                                             0 : CLK_IS_ROOT, req_rate);
+               if (!IS_ERR(clk)) {
+                       adg->clkout[CLKOUT] = clk;
+                       of_clk_add_provider(np, of_clk_src_simple_get, clk);
+               }
+       }
+       /*
+        * for clkout0/1/2/3
+        */
+       else {
+               for (i = 0; i < CLKOUTMAX; i++) {
+                       clk = clk_register_fixed_rate(dev, clkout_name[i],
+                                                     parent_clk_name,
+                                                     (parent_clk_name) ?
+                                                     0 : CLK_IS_ROOT,
+                                                     req_rate);
+                       if (!IS_ERR(clk)) {
+                               adg->onecell.clks       = adg->clkout;
+                               adg->onecell.clk_num    = CLKOUTMAX;
+
+                               adg->clkout[i] = clk;
+
+                               of_clk_add_provider(np, of_clk_src_onecell_get,
+                                                   &adg->onecell);
+                       }
+               }
+       }
+
+       rsnd_mod_bset(adg_mod, SSICKR, 0x00FF0000, ckr);
+       rsnd_mod_write(adg_mod, BRRA,  rbga);
+       rsnd_mod_write(adg_mod, BRRB,  rbgb);
+
+       for_each_rsnd_clkout(clk, adg, i)
+               dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+       dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
+               ckr, rbga, rbgb);
 }
 
 int rsnd_adg_probe(struct platform_device *pdev,
@@ -413,8 +578,6 @@ int rsnd_adg_probe(struct platform_device *pdev,
 {
        struct rsnd_adg *adg;
        struct device *dev = rsnd_priv_to_dev(priv);
-       struct clk *clk;
-       int i;
 
        adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
        if (!adg) {
@@ -422,15 +585,16 @@ int rsnd_adg_probe(struct platform_device *pdev,
                return -ENOMEM;
        }
 
-       adg->clk[CLKA]  = devm_clk_get(dev, "clk_a");
-       adg->clk[CLKB]  = devm_clk_get(dev, "clk_b");
-       adg->clk[CLKC]  = devm_clk_get(dev, "clk_c");
-       adg->clk[CLKI]  = devm_clk_get(dev, "clk_i");
-
-       for_each_rsnd_clk(clk, adg, i)
-               dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+       /*
+        * ADG is special module.
+        * Use ADG mod without rsnd_mod_init() to make debug easy
+        * for rsnd_write/rsnd_read
+        */
+       adg->mod.ops = &adg_ops;
+       adg->mod.priv = priv;
 
-       rsnd_adg_ssi_clk_init(priv, adg);
+       rsnd_adg_get_clkin(priv, adg);
+       rsnd_adg_get_clkout(priv, adg);
 
        priv->adg = adg;
 
index f3feed5ce9b65ba67d936a399a4a06f91cf77db7..deed48ef28b832821010f7192961aaa9af4ba84b 100644 (file)
@@ -110,6 +110,7 @@ static const struct rsnd_of_data rsnd_of_data_gen2 = {
 static const struct of_device_id rsnd_of_match[] = {
        { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
        { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
+       { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
        {},
 };
 MODULE_DEVICE_TABLE(of, rsnd_of_match);
@@ -126,6 +127,17 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match);
 #define rsnd_info_id(priv, io, name) \
        ((io)->info->name - priv->info->name##_info)
 
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
+{
+       if (mod->type != type) {
+               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_warn(dev, "%s[%d] is not your expected module\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+       }
+}
+
 /*
  *     rsnd_mod functions
  */
@@ -288,7 +300,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 /*
  *     rsnd_dai functions
  */
-#define __rsnd_mod_call(mod, io, func, param...)               \
+#define rsnd_mod_call(mod, io, func, param...)                 \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct device *dev = rsnd_priv_to_dev(priv);            \
@@ -296,24 +308,17 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        u8 val  = (mod->status >> __rsnd_mod_shift_##func) & 0xF;       \
        u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);                \
        int ret = 0;                                                    \
-       int called = 0;                                                 \
-       if (val == __rsnd_mod_call_##func) {                            \
-               called = 1;                                             \
-               ret = (mod)->ops->func(mod, io, param);                 \
-       }                                                               \
+       int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
        mod->status = (mod->status & ~mask) +                           \
                (add << __rsnd_mod_shift_##func);                       \
-       dev_dbg(dev, "%s[%d] 0x%08x %s\n",                              \
-               rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status,      \
-               called ? #func : "");                                   \
+       dev_dbg(dev, "%s[%d]\t0x%08x %s\n",                             \
+               rsnd_mod_name(mod), rsnd_mod_id(mod),                   \
+               mod->status, call ? #func : "");                        \
+       if (call)                                                       \
+               ret = (mod)->ops->func(mod, io, param);                 \
        ret;                                                            \
 })
 
-#define rsnd_mod_call(mod, io, func, param...) \
-       (!(mod) ? -ENODEV :                     \
-        !((mod)->ops->func) ? 0 :              \
-        __rsnd_mod_call(mod, io, func, param))
-
 #define rsnd_dai_call(fn, io, param...)                                \
 ({                                                             \
        struct rsnd_mod *mod;                                   \
@@ -322,9 +327,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret = rsnd_mod_call(mod, io, fn, param);        \
-               if (ret < 0)                                    \
-                       break;                                  \
+               ret |= rsnd_mod_call(mod, io, fn, param);       \
        }                                                       \
        ret;                                                    \
 })
@@ -490,16 +493,10 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                ret = rsnd_dai_call(stop, io, priv);
-               if (ret < 0)
-                       goto dai_trigger_end;
 
-               ret = rsnd_dai_call(quit, io, priv);
-               if (ret < 0)
-                       goto dai_trigger_end;
+               ret |= rsnd_dai_call(quit, io, priv);
 
-               ret = rsnd_platform_call(priv, dai, stop, ssi_id);
-               if (ret < 0)
-                       goto dai_trigger_end;
+               ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
 
                rsnd_dai_stream_quit(io);
                break;
@@ -1224,20 +1221,11 @@ static int rsnd_probe(struct platform_device *pdev)
        };
        int ret, i;
 
-       info = NULL;
-       of_data = NULL;
-       if (of_id) {
-               info = devm_kzalloc(&pdev->dev,
-                                   sizeof(struct rcar_snd_info), GFP_KERNEL);
-               of_data = of_id->data;
-       } else {
-               info = pdev->dev.platform_data;
-       }
-
-       if (!info) {
-               dev_err(dev, "driver needs R-Car sound information\n");
-               return -ENODEV;
-       }
+       info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
+                           GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       of_data = of_id->data;
 
        /*
         *      init priv data
index 05498bba5874dbb0fe9fffdb46e26bad0866f045..3cb214ab848be05ca345e0a976e2d1a2d6bdc65b 100644 (file)
@@ -35,7 +35,7 @@ static int rsnd_ctu_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_start(mod);
+       rsnd_mod_power_on(mod);
 
        rsnd_ctu_initialize_lock(mod);
 
@@ -50,7 +50,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_stop(mod);
+       rsnd_mod_power_off(mod);
 
        return 0;
 }
@@ -66,7 +66,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
                id = 0;
 
-       return &((struct rsnd_ctu *)(priv->ctu) + id)->mod;
+       return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
 }
 
 static void rsnd_of_parse_ctu(struct platform_device *pdev,
@@ -118,10 +118,8 @@ int rsnd_ctu_probe(struct platform_device *pdev,
        int i, nr, ret;
 
        /* This driver doesn't support Gen1 at this point */
-       if (rsnd_is_gen1(priv)) {
-               dev_warn(dev, "CTU is not supported on Gen1\n");
-               return -EINVAL;
-       }
+       if (rsnd_is_gen1(priv))
+               return 0;
 
        rsnd_of_parse_ctu(pdev, of_data, priv);
 
@@ -150,7 +148,7 @@ int rsnd_ctu_probe(struct platform_device *pdev,
 
                ctu->info = &info->ctu_info[i];
 
-               ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops,
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
                                    clk, RSND_MOD_CTU, i);
                if (ret)
                        return ret;
@@ -166,6 +164,6 @@ void rsnd_ctu_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_ctu(ctu, priv, i) {
-               rsnd_mod_quit(&ctu->mod);
+               rsnd_mod_quit(rsnd_mod_get(ctu));
        }
 }
index bfbb8a5e93bdce6c5c70092565869bf446233416..5d084d0409611dd67cf35bc00c2fed53b517862b 100644 (file)
@@ -470,7 +470,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
                dev_err(dev, "DVC is selected without SRC\n");
 
        /* use SSIU or SSI ? */
-       if (is_ssi && rsnd_ssi_use_busif(io, mod))
+       if (is_ssi && rsnd_ssi_use_busif(io))
                is_ssi++;
 
        return (is_from) ?
index 57796387d482303bc84c29212dfed167685ae6fe..58f690900e6d36a704be976b5a440550df76726a 100644 (file)
@@ -153,7 +153,7 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_start(mod);
+       rsnd_mod_power_on(mod);
 
        rsnd_dvc_soft_reset(mod);
 
@@ -175,7 +175,7 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_stop(mod);
+       rsnd_mod_power_off(mod);
 
        return 0;
 }
@@ -282,7 +282,7 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
                id = 0;
 
-       return &((struct rsnd_dvc *)(priv->dvc) + id)->mod;
+       return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
 }
 
 static void rsnd_of_parse_dvc(struct platform_device *pdev,
@@ -333,10 +333,8 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        int i, nr, ret;
 
        /* This driver doesn't support Gen1 at this point */
-       if (rsnd_is_gen1(priv)) {
-               dev_warn(dev, "CMD is not supported on Gen1\n");
-               return -EINVAL;
-       }
+       if (rsnd_is_gen1(priv))
+               return 0;
 
        rsnd_of_parse_dvc(pdev, of_data, priv);
 
@@ -361,7 +359,7 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 
                dvc->info = &info->dvc_info[i];
 
-               ret = rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops,
+               ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
                if (ret)
                        return ret;
@@ -377,6 +375,6 @@ void rsnd_dvc_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_dvc(dvc, priv, i) {
-               rsnd_mod_quit(&dvc->mod);
+               rsnd_mod_quit(rsnd_mod_get(dvc));
        }
 }
index f04d17bc6e3debba80a7c69f2d6c51e3daa72ec8..76da7620904c982ee1946f7db9369c7065028133 100644 (file)
 #include "rsnd.h"
 
 struct rsnd_gen {
-       void __iomem *base[RSND_BASE_MAX];
-
        struct rsnd_gen_ops *ops;
 
+       /* RSND_BASE_MAX base */
+       void __iomem *base[RSND_BASE_MAX];
+       phys_addr_t res[RSND_BASE_MAX];
        struct regmap *regmap[RSND_BASE_MAX];
+
+       /* RSND_REG_MAX base */
        struct regmap_field *regs[RSND_REG_MAX];
-       phys_addr_t res[RSND_REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
@@ -79,11 +81,11 @@ u32 rsnd_read(struct rsnd_priv *priv,
        if (!rsnd_is_accessible_reg(priv, gen, reg))
                return 0;
 
+       regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+
        dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
                rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
 
-       regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
-
        return val;
 }
 
@@ -182,6 +184,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
+       /* RSND_BASE_MAX base */
        gen->base[reg_id] = base;
        gen->regmap[reg_id] = regmap;
        gen->res[reg_id] = res->start;
@@ -198,6 +201,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
                if (IS_ERR(regs))
                        return PTR_ERR(regs);
 
+               /* RSND_REG_MAX base */
                gen->regs[conf[i].idx] = regs;
        }
 
index 0d5c102db6f5fb6ed54b05e42f97888bdd0c6c20..953dd0be9b6026d4b21e952c371c5b9ee3d65a08 100644 (file)
@@ -58,7 +58,7 @@ static int rsnd_mix_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_start(mod);
+       rsnd_mod_power_on(mod);
 
        rsnd_mix_soft_reset(mod);
 
@@ -83,7 +83,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_hw_stop(mod);
+       rsnd_mod_power_off(mod);
 
        return 0;
 }
@@ -99,7 +99,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
                id = 0;
 
-       return &((struct rsnd_mix *)(priv->mix) + id)->mod;
+       return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
 }
 
 static void rsnd_of_parse_mix(struct platform_device *pdev,
@@ -151,10 +151,8 @@ int rsnd_mix_probe(struct platform_device *pdev,
        int i, nr, ret;
 
        /* This driver doesn't support Gen1 at this point */
-       if (rsnd_is_gen1(priv)) {
-               dev_warn(dev, "MIX is not supported on Gen1\n");
-               return -EINVAL;
-       }
+       if (rsnd_is_gen1(priv))
+               return 0;
 
        rsnd_of_parse_mix(pdev, of_data, priv);
 
@@ -179,7 +177,7 @@ int rsnd_mix_probe(struct platform_device *pdev,
 
                mix->info = &info->mix_info[i];
 
-               ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops,
+               ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
                                    clk, RSND_MOD_MIX, i);
                if (ret)
                        return ret;
@@ -195,6 +193,6 @@ void rsnd_mix_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_mix(mix, priv, i) {
-               rsnd_mod_quit(&mix->mod);
+               rsnd_mod_quit(rsnd_mod_get(mix));
        }
 }
diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h
new file mode 100644 (file)
index 0000000..d8e33d3
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RCAR_SND_H
+#define RCAR_SND_H
+
+
+#define RSND_GEN1_SRU  0
+#define RSND_GEN1_ADG  1
+#define RSND_GEN1_SSI  2
+
+#define RSND_GEN2_SCU  0
+#define RSND_GEN2_ADG  1
+#define RSND_GEN2_SSIU 2
+#define RSND_GEN2_SSI  3
+
+#define RSND_BASE_MAX  4
+
+/*
+ * flags
+ *
+ * 0xAB000000
+ *
+ * A : clock sharing settings
+ * B : SSI direction
+ */
+#define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
+#define RSND_SSI_NO_BUSIF              (1 << 30) /* SSI+DMA without BUSIF */
+
+#define RSND_SSI(_dma_id, _irq, _flags)                \
+{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
+#define RSND_SSI_UNUSED \
+{ .dma_id = -1, .irq = -1, .flags = 0 }
+
+struct rsnd_ssi_platform_info {
+       int dma_id;
+       int irq;
+       u32 flags;
+};
+
+#define RSND_SRC(rate, _dma_id)                                                \
+{ .convert_rate = rate, .dma_id = _dma_id, }
+#define RSND_SRC_UNUSED                                \
+{ .convert_rate = 0, .dma_id = -1, }
+
+struct rsnd_src_platform_info {
+       u32 convert_rate; /* sampling rate convert */
+       int dma_id; /* for Gen2 SCU */
+       int irq;
+};
+
+/*
+ * flags
+ */
+struct rsnd_ctu_platform_info {
+       u32 flags;
+};
+
+struct rsnd_mix_platform_info {
+       u32 flags;
+};
+
+struct rsnd_dvc_platform_info {
+       u32 flags;
+};
+
+struct rsnd_dai_path_info {
+       struct rsnd_ssi_platform_info *ssi;
+       struct rsnd_src_platform_info *src;
+       struct rsnd_ctu_platform_info *ctu;
+       struct rsnd_mix_platform_info *mix;
+       struct rsnd_dvc_platform_info *dvc;
+};
+
+struct rsnd_dai_platform_info {
+       struct rsnd_dai_path_info playback;
+       struct rsnd_dai_path_info capture;
+};
+
+/*
+ * flags
+ *
+ * 0x0000000A
+ *
+ * A : generation
+ */
+#define RSND_GEN_MASK  (0xF << 0)
+#define RSND_GEN1      (1 << 0) /* fixme */
+#define RSND_GEN2      (2 << 0) /* fixme */
+
+struct rcar_snd_info {
+       u32 flags;
+       struct rsnd_ssi_platform_info *ssi_info;
+       int ssi_info_nr;
+       struct rsnd_src_platform_info *src_info;
+       int src_info_nr;
+       struct rsnd_ctu_platform_info *ctu_info;
+       int ctu_info_nr;
+       struct rsnd_mix_platform_info *mix_info;
+       int mix_info_nr;
+       struct rsnd_dvc_platform_info *dvc_info;
+       int dvc_info_nr;
+       struct rsnd_dai_platform_info *dai_info;
+       int dai_info_nr;
+       int (*start)(int id);
+       int (*stop)(int id);
+};
+
+#endif
index 7a0e52b4640a5a39a0bfb3f1d496d71919e0806c..08532987852516cea79ed04051bf9b7ba62f3e51 100644 (file)
 #include <linux/of_irq.h>
 #include <linux/sh_dma.h>
 #include <linux/workqueue.h>
-#include <sound/rcar_snd.h>
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
+#include "rcar_snd.h"
+
 /*
  *     pseudo register
  *
@@ -214,6 +215,7 @@ struct rsnd_dma {
 };
 #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
 #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
+#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 
 void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
 void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
@@ -225,8 +227,6 @@ int rsnd_dma_probe(struct platform_device *pdev,
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
                                          struct rsnd_mod *mod, char *name);
 
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
-
 /*
  *     R-Car sound mod
  */
@@ -330,8 +330,9 @@ struct rsnd_mod {
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
-#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
-#define rsnd_mod_hw_stop(mod)  clk_disable((mod)->clk)
+#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
+#define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
+#define rsnd_mod_get(ip)       (&(ip)->mod)
 
 int rsnd_mod_init(struct rsnd_priv *priv,
                  struct rsnd_mod *mod,
@@ -571,9 +572,12 @@ int rsnd_ssi_probe(struct platform_device *pdev,
 void rsnd_ssi_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+
+#define rsnd_ssi_is_pin_sharing(io)    \
+       __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 
 /*
  *     R-Car SRC
@@ -627,4 +631,15 @@ void rsnd_dvc_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
 
+#ifdef DEBUG
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
+#define rsnd_mod_confirm_ssi(mssi)     rsnd_mod_make_sure(mssi, RSND_MOD_SSI)
+#define rsnd_mod_confirm_src(msrc)     rsnd_mod_make_sure(msrc, RSND_MOD_SRC)
+#define rsnd_mod_confirm_dvc(mdvc)     rsnd_mod_make_sure(mdvc, RSND_MOD_DVC)
+#else
+#define rsnd_mod_confirm_ssi(mssi)
+#define rsnd_mod_confirm_src(msrc)
+#define rsnd_mod_confirm_dvc(mdvc)
+#endif
+
 #endif
index 89a18e102feb100b57350024a3d548261e91243e..261b50217c48d94f0a66f44c513f685755ddae07 100644 (file)
@@ -159,7 +159,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
        /*
         * SSI_MODE1
         */
-       if (rsnd_ssi_is_pin_sharing(ssi_mod)) {
+       if (rsnd_ssi_is_pin_sharing(io)) {
                int shift = -1;
                switch (ssi_id) {
                case 1:
@@ -352,7 +352,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       rsnd_mod_hw_start(mod);
+       rsnd_mod_power_on(mod);
 
        rsnd_src_soft_reset(mod);
 
@@ -373,7 +373,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
-       rsnd_mod_hw_stop(mod);
+       rsnd_mod_power_off(mod);
 
        if (src->err)
                dev_warn(dev, "%s[%d] under/over flow err = %d\n",
@@ -918,11 +918,10 @@ static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
        rsnd_mod_write(mod, SRC_IFSVR, fsrate);
 }
 
-static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
@@ -931,12 +930,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
         * enable SRC sync convert if possible
         */
 
-       /*
-        * Gen1 is not supported
-        */
-       if (rsnd_is_gen1(priv))
-               return 0;
-
        /*
         * SRC sync convert needs clock master
         */
@@ -975,7 +968,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = {
        .start  = rsnd_src_start_gen2,
        .stop   = rsnd_src_stop_gen2,
        .hw_params = rsnd_src_hw_params,
-       .pcm_new = rsnd_src_pcm_new,
+       .pcm_new = rsnd_src_pcm_new_gen2,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -983,7 +976,7 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
                id = 0;
 
-       return &((struct rsnd_src *)(priv->src) + id)->mod;
+       return rsnd_mod_get((struct rsnd_src *)(priv->src) + id);
 }
 
 static void rsnd_of_parse_src(struct platform_device *pdev,
@@ -1043,8 +1036,10 @@ int rsnd_src_probe(struct platform_device *pdev,
        int i, nr, ret;
 
        ops = NULL;
-       if (rsnd_is_gen1(priv))
+       if (rsnd_is_gen1(priv)) {
                ops = &rsnd_src_gen1_ops;
+               dev_warn(dev, "Gen1 support will be removed soon\n");
+       }
        if (rsnd_is_gen2(priv))
                ops = &rsnd_src_gen2_ops;
        if (!ops) {
@@ -1078,7 +1073,7 @@ int rsnd_src_probe(struct platform_device *pdev,
 
                src->info = &info->src_info[i];
 
-               ret = rsnd_mod_init(priv, &src->mod, ops, clk, RSND_MOD_SRC, i);
+               ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i);
                if (ret)
                        return ret;
        }
@@ -1093,6 +1088,6 @@ void rsnd_src_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_src(src, priv, i) {
-               rsnd_mod_quit(&src->mod);
+               rsnd_mod_quit(rsnd_mod_get(src));
        }
 }
index d45b9a7e324efb49a5159417232c9f43815ebfed..1427ec21bd7ee1f581ef3ef4109716e3175ee066 100644 (file)
@@ -79,7 +79,6 @@ struct rsnd_ssi {
 
 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
 #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
 #define rsnd_ssi_parent(ssi) ((ssi)->parent)
 #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
@@ -87,8 +86,9 @@ struct rsnd_ssi {
 #define rsnd_ssi_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
 
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 {
+       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        int use_busif = 0;
 
@@ -128,10 +128,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
-       int i, j, ret;
-       int adg_clk_div_table[] = {
-               1, 6, /* see adg.c */
-       };
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       int j, ret;
        int ssi_clk_mul_table[] = {
                1, 2, 4, 8, 16, 6, 12,
        };
@@ -141,28 +139,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
        /*
         * Find best clock, and try to start ADG
         */
-       for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
-               for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
-
-                       /*
-                        * this driver is assuming that
-                        * system word is 64fs (= 2 x 32bit)
-                        * see rsnd_ssi_init()
-                        */
-                       main_rate = rate / adg_clk_div_table[i]
-                               * 32 * 2 * ssi_clk_mul_table[j];
-
-                       ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
-                       if (0 == ret) {
-                               ssi->cr_clk     = FORCE | SWL_32 |
-                                                 SCKD | SWSD | CKDV(j);
-
-                               dev_dbg(dev, "%s[%d] outputs %u Hz\n",
-                                       rsnd_mod_name(&ssi->mod),
-                                       rsnd_mod_id(&ssi->mod), rate);
-
-                               return 0;
-                       }
+       for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+               /*
+                * this driver is assuming that
+                * system word is 64fs (= 2 x 32bit)
+                * see rsnd_ssi_init()
+                */
+               main_rate = rate * 32 * 2 * ssi_clk_mul_table[j];
+
+               ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
+               if (0 == ret) {
+                       ssi->cr_clk     = FORCE | SWL_32 |
+                               SCKD | SWSD | CKDV(j);
+
+                       dev_dbg(dev, "%s[%d] outputs %u Hz\n",
+                               rsnd_mod_name(mod),
+                               rsnd_mod_id(mod), rate);
+
+                       return 0;
                }
        }
 
@@ -172,8 +167,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
 static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
 {
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
        ssi->cr_clk = 0;
-       rsnd_adg_ssi_clk_stop(&ssi->mod);
+       rsnd_adg_ssi_clk_stop(mod);
 }
 
 static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
@@ -182,11 +179,12 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
        u32 cr_mode;
        u32 cr;
 
        if (0 == ssi->usrcnt) {
-               rsnd_mod_hw_start(&ssi->mod);
+               rsnd_mod_power_on(mod);
 
                if (rsnd_rdai_is_clk_master(rdai)) {
                        struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
@@ -198,7 +196,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                }
        }
 
-       if (rsnd_ssi_is_dma_mode(&ssi->mod)) {
+       if (rsnd_ssi_is_dma_mode(mod)) {
                cr_mode = UIEN | OIEN | /* over/under run */
                          DMEN;         /* DMA : enable DMA */
        } else {
@@ -210,24 +208,25 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                cr_mode         |
                EN;
 
-       rsnd_mod_write(&ssi->mod, SSICR, cr);
+       rsnd_mod_write(mod, SSICR, cr);
 
        /* enable WS continue */
        if (rsnd_rdai_is_clk_master(rdai))
-               rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+               rsnd_mod_write(mod, SSIWSR, CONT);
 
        /* clear error status */
-       rsnd_mod_write(&ssi->mod, SSISR, 0);
+       rsnd_mod_write(mod, SSISR, 0);
 
        ssi->usrcnt++;
 
        dev_dbg(dev, "%s[%d] hw started\n",
-               rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
 }
 
 static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr;
@@ -247,15 +246,15 @@ static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
                cr  =   ssi->cr_own     |
                        ssi->cr_clk;
 
-               rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
-               rsnd_ssi_status_check(&ssi->mod, DIRQ);
+               rsnd_mod_write(mod, SSICR, cr | EN);
+               rsnd_ssi_status_check(mod, DIRQ);
 
                /*
                 * disable SSI,
                 * and, wait idle state
                 */
-               rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
-               rsnd_ssi_status_check(&ssi->mod, IIRQ);
+               rsnd_mod_write(mod, SSICR, cr); /* disabled all */
+               rsnd_ssi_status_check(mod, IIRQ);
 
                if (rsnd_rdai_is_clk_master(rdai)) {
                        struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
@@ -266,13 +265,13 @@ static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
                                rsnd_ssi_master_clk_stop(ssi);
                }
 
-               rsnd_mod_hw_stop(&ssi->mod);
+               rsnd_mod_power_off(mod);
 
                ssi->chan = 0;
        }
 
        dev_dbg(dev, "%s[%d] hw stopped\n",
-               rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
 }
 
 /*
@@ -371,7 +370,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
        /* It will be removed on rsnd_ssi_hw_stop */
        ssi->chan = chan;
        if (ssi_parent)
-               return rsnd_ssi_hw_params(&ssi_parent->mod, io,
+               return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
                                          substream, params);
 
        return 0;
@@ -379,12 +378,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
 
 static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 {
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
        /* under/over flow error */
        if (status & (UIRQ | OIRQ)) {
                ssi->err++;
 
                /* clear error status */
-               rsnd_mod_write(&ssi->mod, SSISR, 0);
+               rsnd_mod_write(mod, SSISR, 0);
        }
 }
 
@@ -394,7 +395,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io, mod));
+       rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io));
 
        rsnd_ssi_hw_start(ssi, io);
 
@@ -554,7 +555,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
        rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
 
        /* PIO will request IRQ again */
-       devm_free_irq(dev, irq, ssi);
+       devm_free_irq(dev, irq, mod);
 
        return 0;
 }
@@ -613,7 +614,7 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
        int is_play = rsnd_io_is_play(io);
        char *name;
 
-       if (rsnd_ssi_use_busif(io, mod))
+       if (rsnd_ssi_use_busif(io))
                name = is_play ? "rxu" : "txu";
        else
                name = is_play ? "rx" : "tx";
@@ -656,10 +657,10 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
                id = 0;
 
-       return &((struct rsnd_ssi *)(priv->ssi) + id)->mod;
+       return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id);
 }
 
-int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
@@ -668,10 +669,12 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
 
 static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
 {
-       if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
+       struct rsnd_mod *mod = rsnd_mod_get(ssi);
+
+       if (!__rsnd_ssi_is_pin_sharing(mod))
                return;
 
-       switch (rsnd_mod_id(&ssi->mod)) {
+       switch (rsnd_mod_id(mod)) {
        case 1:
        case 2:
                ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
@@ -697,9 +700,6 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
        struct device *dev = &pdev->dev;
        int nr, i;
 
-       if (!of_data)
-               return;
-
        node = rsnd_ssi_of_node(priv);
        if (!node)
                return;
@@ -794,7 +794,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               ret = rsnd_mod_init(priv, &ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
+                                   RSND_MOD_SSI, i);
                if (ret)
                        return ret;
 
@@ -811,6 +812,6 @@ void rsnd_ssi_remove(struct platform_device *pdev,
        int i;
 
        for_each_rsnd_ssi(ssi, priv, i) {
-               rsnd_mod_quit(&ssi->mod);
+               rsnd_mod_quit(rsnd_mod_get(ssi));
        }
 }
index abb0d956231ca1235333ffd516595ca8fc5b083d..76b2ab8c2b4a4f964307b9832677ebb8a4961464 100644 (file)
@@ -738,7 +738,7 @@ static int siu_probe(struct platform_device *pdev)
        struct siu_info *info;
        int ret;
 
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
        siu_i2s_data = info;
@@ -746,7 +746,7 @@ static int siu_probe(struct platform_device *pdev)
 
        ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
        if (ret)
-               goto ereqfw;
+               return ret;
 
        /*
         * Loaded firmware is "const" - read only, but we have to modify it in
@@ -757,89 +757,52 @@ static int siu_probe(struct platform_device *pdev)
        release_firmware(fw_entry);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto egetres;
-       }
+       if (!res)
+               return -ENODEV;
 
-       region = request_mem_region(res->start, resource_size(res),
-                                   pdev->name);
+       region = devm_request_mem_region(&pdev->dev, res->start,
+                                        resource_size(res), pdev->name);
        if (!region) {
                dev_err(&pdev->dev, "SIU region already claimed\n");
-               ret = -EBUSY;
-               goto ereqmemreg;
+               return -EBUSY;
        }
 
-       ret = -ENOMEM;
-       info->pram = ioremap(res->start, PRAM_SIZE);
+       info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);
        if (!info->pram)
-               goto emappram;
-       info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE);
+               return -ENOMEM;
+       info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,
+                                 XRAM_SIZE);
        if (!info->xram)
-               goto emapxram;
-       info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE);
+               return -ENOMEM;
+       info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,
+                                 YRAM_SIZE);
        if (!info->yram)
-               goto emapyram;
-       info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) -
-                           REG_OFFSET);
+               return -ENOMEM;
+       info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,
+                           resource_size(res) - REG_OFFSET);
        if (!info->reg)
-               goto emapreg;
+               return -ENOMEM;
 
        dev_set_drvdata(&pdev->dev, info);
 
        /* register using ARRAY version so we can keep dai name */
-       ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component,
-                                        &siu_i2s_dai, 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+                                             &siu_i2s_dai, 1);
        if (ret < 0)
-               goto edaiinit;
+               return ret;
 
-       ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
+       ret = devm_snd_soc_register_platform(&pdev->dev, &siu_platform);
        if (ret < 0)
-               goto esocregp;
+               return ret;
 
        pm_runtime_enable(&pdev->dev);
 
-       return ret;
-
-esocregp:
-       snd_soc_unregister_component(&pdev->dev);
-edaiinit:
-       iounmap(info->reg);
-emapreg:
-       iounmap(info->yram);
-emapyram:
-       iounmap(info->xram);
-emapxram:
-       iounmap(info->pram);
-emappram:
-       release_mem_region(res->start, resource_size(res));
-ereqmemreg:
-egetres:
-ereqfw:
-       kfree(info);
-
-       return ret;
+       return 0;
 }
 
 static int siu_remove(struct platform_device *pdev)
 {
-       struct siu_info *info = dev_get_drvdata(&pdev->dev);
-       struct resource *res;
-
        pm_runtime_disable(&pdev->dev);
-
-       snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_component(&pdev->dev);
-
-       iounmap(info->reg);
-       iounmap(info->yram);
-       iounmap(info->xram);
-       iounmap(info->pram);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-       kfree(info);
-
        return 0;
 }
 
index 025c38fbe3c03fea08db0b365e472902c5f110fc..12a9820feac1548d5c3d3cbc50e0a8cc2bfefc25 100644 (file)
@@ -612,8 +612,15 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
        .get_codec_caps = soc_compr_get_codec_caps
 };
 
-/* create a new compress */
-int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
+/**
+ * snd_soc_new_compress - create a new compress.
+ *
+ * @rtd: The runtime for which we will create compress
+ * @num: the device index number (zero based - shared with normal PCMs)
+ *
+ * Return: 0 for success, else error.
+ */
+int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_platform *platform = rtd->platform;
@@ -703,3 +710,4 @@ compr_err:
        kfree(compr);
        return ret;
 }
+EXPORT_SYMBOL_GPL(snd_soc_new_compress);
index 6173d15236c3c0c2ce53c3c31b721310f9576e9e..24b096066a07205c88e377e28f94eacff1261f3e 100644 (file)
@@ -1370,9 +1370,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                soc_dpcm_debugfs_add(rtd);
 #endif
 
-       if (cpu_dai->driver->compress_dai) {
+       if (cpu_dai->driver->compress_new) {
                /*create compress_device"*/
-               ret = soc_new_compress(rtd, num);
+               ret = cpu_dai->driver->compress_new(rtd, num);
                if (ret < 0) {
                        dev_err(card->dev, "ASoC: can't create compress %s\n",
                                         dai_link->stream_name);
@@ -3291,13 +3291,38 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
 
+static int snd_soc_of_get_slot_mask(struct device_node *np,
+                                   const char *prop_name,
+                                   unsigned int *mask)
+{
+       u32 val;
+       const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
+       int i;
+
+       if (!of_slot_mask)
+               return 0;
+       val /= sizeof(u32);
+       for (i = 0; i < val; i++)
+               if (be32_to_cpup(&of_slot_mask[i]))
+                       *mask |= (1 << i);
+
+       return val;
+}
+
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *tx_mask,
+                             unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width)
 {
        u32 val;
        int ret;
 
+       if (tx_mask)
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
+       if (rx_mask)
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
+
        if (of_property_read_bool(np, "dai-tdm-slot-num")) {
                ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
                if (ret)
index ff8bda471b2531fede57ea0dd225bc4081d5ba16..016eba10b1ec2744a8b9b1b3492d6c0fa1c7a561 100644 (file)
@@ -508,6 +508,18 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
        return true;
 }
 
+/**
+ * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
+ *   kcontrol
+ * @kcontrol: The kcontrol
+ */
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
+                               struct snd_kcontrol *kcontrol)
+{
+       return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
+
 /**
  * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
  *  kcontrol
@@ -779,7 +791,7 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
  */
-static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
+static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
        int kci)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
@@ -810,6 +822,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        switch (w->id) {
                        case snd_soc_dapm_switch:
                        case snd_soc_dapm_mixer:
+                       case snd_soc_dapm_pga:
                                wname_in_long_name = true;
                                kcname_in_long_name = true;
                                break;
@@ -899,7 +912,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
                                continue;
 
                        if (!w->kcontrols[i]) {
-                               ret = dapm_create_or_share_mixmux_kcontrol(w, i);
+                               ret = dapm_create_or_share_kcontrol(w, i);
                                if (ret < 0)
                                        return ret;
                        }
@@ -952,7 +965,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
                return -EINVAL;
        }
 
-       ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
+       ret = dapm_create_or_share_kcontrol(w, 0);
        if (ret < 0)
                return ret;
 
@@ -967,9 +980,13 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 /* create new dapm volume control */
 static int dapm_new_pga(struct snd_soc_dapm_widget *w)
 {
-       if (w->num_kcontrols)
-               dev_err(w->dapm->dev,
-                       "ASoC: PGA controls not supported: '%s'\n", w->name);
+       int i, ret;
+
+       for (i = 0; i < w->num_kcontrols; i++) {
+               ret = dapm_create_or_share_kcontrol(w, i);
+               if (ret < 0)
+                       return ret;
+       }
 
        return 0;
 }
@@ -3473,11 +3490,29 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+               if (source->driver->ops && source->driver->ops->startup) {
+                       ret = source->driver->ops->startup(&substream, source);
+                       if (ret < 0) {
+                               dev_err(source->dev,
+                                       "ASoC: startup() failed: %d\n", ret);
+                               goto out;
+                       }
+                       source->active++;
+               }
                ret = soc_dai_hw_params(&substream, params, source);
                if (ret < 0)
                        goto out;
 
                substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+               if (sink->driver->ops && sink->driver->ops->startup) {
+                       ret = sink->driver->ops->startup(&substream, sink);
+                       if (ret < 0) {
+                               dev_err(sink->dev,
+                                       "ASoC: startup() failed: %d\n", ret);
+                               goto out;
+                       }
+                       sink->active++;
+               }
                ret = soc_dai_hw_params(&substream, params, sink);
                if (ret < 0)
                        goto out;
@@ -3497,6 +3532,18 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
                if (ret != 0 && ret != -ENOTSUPP)
                        dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
                ret = 0;
+
+               source->active--;
+               if (source->driver->ops && source->driver->ops->shutdown) {
+                       substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+                       source->driver->ops->shutdown(&substream, source);
+               }
+
+               sink->active--;
+               if (sink->driver->ops && sink->driver->ops->shutdown) {
+                       substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+                       sink->driver->ops->shutdown(&substream, sink);
+               }
                break;
 
        default:
index 05977ae1ff2a3250c3fe2043b8124f9370dd1542..ecd38e52285a964d53fce4c5c0d4ae71fd4bc15d 100644 (file)
@@ -588,16 +588,16 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
 /**
  * snd_soc_limit_volume - Set new limit to an existing volume control.
  *
- * @codec: where to look for the control
+ * @card: where to look for the control
  * @name: Name of the control
  * @max: new maximum limit
  *
  * Return 0 for success, else error.
  */
-int snd_soc_limit_volume(struct snd_soc_codec *codec,
+int snd_soc_limit_volume(struct snd_soc_card *card,
        const char *name, int max)
 {
-       struct snd_card *card = codec->component.card->snd_card;
+       struct snd_card *snd_card = card->snd_card;
        struct snd_kcontrol *kctl;
        struct soc_mixer_control *mc;
        int found = 0;
@@ -607,7 +607,7 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
        if (unlikely(!name || max <= 0))
                return -EINVAL;
 
-       list_for_each_entry(kctl, &card->controls, list) {
+       list_for_each_entry(kctl, &snd_card->controls, list) {
                if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) {
                        found = 1;
                        break;
index 70e4b9d8bdcdfd3fb83f37615a29fae64036d4c0..c86dc96e8986f39cd08bcf7e92c63f49459d50f2 100644 (file)
 
 #define DPCM_MAX_BE_USERS      8
 
+/*
+ * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
+ *
+ * Returns true if the DAI supports the indicated stream type.
+ */
+static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
+{
+       struct snd_soc_pcm_stream *codec_stream;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               codec_stream = &dai->driver->playback;
+       else
+               codec_stream = &dai->driver->capture;
+
+       /* If the codec specifies any rate at all, it supports the stream. */
+       return codec_stream->rates;
+}
+
 /**
  * snd_soc_runtime_activate() - Increment active count for PCM runtime components
  * @rtd: ASoC PCM runtime that is activated
@@ -182,9 +200,9 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
                                soc_dai->rate);
 
-               ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+               ret = snd_pcm_hw_constraint_single(substream->runtime,
                                                SNDRV_PCM_HW_PARAM_RATE,
-                                               soc_dai->rate, soc_dai->rate);
+                                               soc_dai->rate);
                if (ret < 0) {
                        dev_err(soc_dai->dev,
                                "ASoC: Unable to apply rate constraint: %d\n",
@@ -198,9 +216,8 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
                                soc_dai->channels);
 
-               ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+               ret = snd_pcm_hw_constraint_single(substream->runtime,
                                                SNDRV_PCM_HW_PARAM_CHANNELS,
-                                               soc_dai->channels,
                                                soc_dai->channels);
                if (ret < 0) {
                        dev_err(soc_dai->dev,
@@ -215,9 +232,8 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
                                soc_dai->sample_bits);
 
-               ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+               ret = snd_pcm_hw_constraint_single(substream->runtime,
                                                SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                               soc_dai->sample_bits,
                                                soc_dai->sample_bits);
                if (ret < 0) {
                        dev_err(soc_dai->dev,
@@ -371,6 +387,20 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
 
        /* first calculate min/max only for CODECs in the DAI link */
        for (i = 0; i < rtd->num_codecs; i++) {
+
+               /*
+                * Skip CODECs which don't support the current stream type.
+                * Otherwise, since the rate, channel, and format values will
+                * zero in that case, we would have no usable settings left,
+                * causing the resulting setup to fail.
+                * At least one CODEC should match, otherwise we should have
+                * bailed out on a higher level, since there would be no
+                * CODEC to support the transfer direction in that case.
+                */
+               if (!snd_soc_dai_stream_valid(rtd->codec_dais[i],
+                                             substream->stream))
+                       continue;
+
                codec_dai_drv = rtd->codec_dais[i]->driver;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                        codec_stream = &codec_dai_drv->playback;
@@ -827,6 +857,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
                struct snd_pcm_hw_params codec_params;
 
+               /*
+                * Skip CODECs which don't support the current stream type,
+                * the idea being that if a CODEC is not used for the currently
+                * set up transfer direction, it should not need to be
+                * configured, especially since the configuration used might
+                * not even be supported by that CODEC. There may be cases
+                * however where a CODEC needs to be set up although it is
+                * actually not being used for the transfer, e.g. if a
+                * capture-only CODEC is acting as an LRCLK and/or BCLK master
+                * for the DAI link including a playback-only CODEC.
+                * If this becomes necessary, we will have to augment the
+                * machine driver setup with information on how to act, so
+                * we can do the right thing here.
+                */
+               if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
+                       continue;
+
                /* copy params for each codec */
                codec_params = *params;
 
index 69d01cd925ce28fb5fc5e798880f391ec207fff0..8d7ec80af51b499738dc2032356896a08144078a 100644 (file)
@@ -1558,7 +1558,7 @@ static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
        pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos;
 
        if (soc_tplg_check_elem_count(tplg,
-               sizeof(struct snd_soc_tplg_pcm_dai), count,
+               sizeof(struct snd_soc_tplg_pcm), count,
                hdr->payload_size, "PCM DAI")) {
                dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
                        count);
@@ -1566,7 +1566,7 @@ static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
        }
 
        dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
-       tplg->pos += sizeof(struct snd_soc_tplg_pcm_dai) * count;
+       tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count;
 
        dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL);
        if (dobj == NULL)
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
new file mode 100644 (file)
index 0000000..84c72ec
--- /dev/null
@@ -0,0 +1,11 @@
+menu "Allwinner SoC Audio support"
+
+config SND_SUN4I_CODEC
+       tristate "Allwinner A10 Codec Support"
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       select REGMAP_MMIO
+       help
+         Select Y or M to add support for the Codec embedded in the Allwinner
+         A10 and affiliated SoCs.
+
+endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
new file mode 100644 (file)
index 0000000..ea8a08c
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
+
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
new file mode 100644 (file)
index 0000000..bcbf4da
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2014 Emilio López <emilio@elopez.com.ar>
+ * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
+ * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+/* Codec DAC register offsets and bit fields */
+#define SUN4I_CODEC_DAC_DPC                    (0x00)
+#define SUN4I_CODEC_DAC_DPC_EN_DA                      (31)
+#define SUN4I_CODEC_DAC_DPC_DVOL                       (12)
+#define SUN4I_CODEC_DAC_FIFOC                  (0x04)
+#define SUN4I_CODEC_DAC_FIFOC_DAC_FS                   (29)
+#define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION              (28)
+#define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT               (26)
+#define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE             (24)
+#define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT              (21)
+#define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL            (8)
+#define SUN4I_CODEC_DAC_FIFOC_MONO_EN                  (6)
+#define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS           (5)
+#define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN               (4)
+#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH               (0)
+#define SUN4I_CODEC_DAC_FIFOS                  (0x08)
+#define SUN4I_CODEC_DAC_TXDATA                 (0x0c)
+#define SUN4I_CODEC_DAC_ACTL                   (0x10)
+#define SUN4I_CODEC_DAC_ACTL_DACAENR                   (31)
+#define SUN4I_CODEC_DAC_ACTL_DACAENL                   (30)
+#define SUN4I_CODEC_DAC_ACTL_MIXEN                     (29)
+#define SUN4I_CODEC_DAC_ACTL_LDACLMIXS                 (15)
+#define SUN4I_CODEC_DAC_ACTL_RDACRMIXS                 (14)
+#define SUN4I_CODEC_DAC_ACTL_LDACRMIXS                 (13)
+#define SUN4I_CODEC_DAC_ACTL_DACPAS                    (8)
+#define SUN4I_CODEC_DAC_ACTL_MIXPAS                    (7)
+#define SUN4I_CODEC_DAC_ACTL_PA_MUTE                   (6)
+#define SUN4I_CODEC_DAC_ACTL_PA_VOL                    (0)
+#define SUN4I_CODEC_DAC_TUNE                   (0x14)
+#define SUN4I_CODEC_DAC_DEBUG                  (0x18)
+
+/* Codec ADC register offsets and bit fields */
+#define SUN4I_CODEC_ADC_FIFOC                  (0x1c)
+#define SUN4I_CODEC_ADC_FIFOC_EN_AD                    (28)
+#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE             (24)
+#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL            (8)
+#define SUN4I_CODEC_ADC_FIFOC_MONO_EN                  (7)
+#define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS           (6)
+#define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN               (4)
+#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH               (0)
+#define SUN4I_CODEC_ADC_FIFOS                  (0x20)
+#define SUN4I_CODEC_ADC_RXDATA                 (0x24)
+#define SUN4I_CODEC_ADC_ACTL                   (0x28)
+#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN                  (31)
+#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN                  (30)
+#define SUN4I_CODEC_ADC_ACTL_PREG1EN                   (29)
+#define SUN4I_CODEC_ADC_ACTL_PREG2EN                   (28)
+#define SUN4I_CODEC_ADC_ACTL_VMICEN                    (27)
+#define SUN4I_CODEC_ADC_ACTL_VADCG                     (20)
+#define SUN4I_CODEC_ADC_ACTL_ADCIS                     (17)
+#define SUN4I_CODEC_ADC_ACTL_PA_EN                     (4)
+#define SUN4I_CODEC_ADC_ACTL_DDE                       (3)
+#define SUN4I_CODEC_ADC_DEBUG                  (0x2c)
+
+/* Other various ADC registers */
+#define SUN4I_CODEC_DAC_TXCNT                  (0x30)
+#define SUN4I_CODEC_ADC_RXCNT                  (0x34)
+#define SUN4I_CODEC_AC_SYS_VERI                        (0x38)
+#define SUN4I_CODEC_AC_MIC_PHONE_CAL           (0x3c)
+
+struct sun4i_codec {
+       struct device   *dev;
+       struct regmap   *regmap;
+       struct clk      *clk_apb;
+       struct clk      *clk_module;
+
+       struct snd_dmaengine_dai_dma_data       playback_dma_data;
+};
+
+static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
+{
+       /*
+        * FIXME: according to the BSP, we might need to drive a PA
+        *        GPIO high here on some boards
+        */
+
+       /* Flush TX FIFO */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
+                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
+
+       /* Enable DAC DRQ */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
+                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
+}
+
+static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
+{
+       /*
+        * FIXME: according to the BSP, we might need to drive a PA
+        *        GPIO low here on some boards
+        */
+
+       /* Disable DAC DRQ */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
+                          0);
+}
+
+static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENOTSUPP;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sun4i_codec_start_playback(scodec);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sun4i_codec_stop_playback(scodec);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+       u32 val;
+
+       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENOTSUPP;
+
+       /* Flush the TX FIFO */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
+                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
+
+       /* Set TX FIFO Empty Trigger Level */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
+                          0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
+
+       if (substream->runtime->rate > 32000)
+               /* Use 64 bits FIR filter */
+               val = 0;
+       else
+               /* Use 32 bits FIR filter */
+               val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
+
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
+                          val);
+
+       /* Send zeros when we have an underrun */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
+                          0);
+
+       return 0;
+}
+
+static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
+{
+       unsigned int rate = params_rate(params);
+
+       switch (rate) {
+       case 176400:
+       case 88200:
+       case 44100:
+       case 33075:
+       case 22050:
+       case 14700:
+       case 11025:
+       case 7350:
+               return 22579200;
+
+       case 192000:
+       case 96000:
+       case 48000:
+       case 32000:
+       case 24000:
+       case 16000:
+       case 12000:
+       case 8000:
+               return 24576000;
+
+       default:
+               return 0;
+       }
+}
+
+static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+{
+       unsigned int rate = params_rate(params);
+
+       switch (rate) {
+       case 192000:
+       case 176400:
+               return 6;
+
+       case 96000:
+       case 88200:
+               return 7;
+
+       case 48000:
+       case 44100:
+               return 0;
+
+       case 32000:
+       case 33075:
+               return 1;
+
+       case 24000:
+       case 22050:
+               return 2;
+
+       case 16000:
+       case 14700:
+               return 3;
+
+       case 12000:
+       case 11025:
+               return 4;
+
+       case 8000:
+       case 7350:
+               return 5;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sun4i_codec_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 sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+       unsigned long clk_freq;
+       int ret, hwrate;
+       u32 val;
+
+       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENOTSUPP;
+
+       clk_freq = sun4i_codec_get_mod_freq(params);
+       if (!clk_freq)
+               return -EINVAL;
+
+       ret = clk_set_rate(scodec->clk_module, clk_freq);
+       if (ret)
+               return ret;
+
+       hwrate = sun4i_codec_get_hw_rate(params);
+       if (hwrate < 0)
+               return hwrate;
+
+       /* Set DAC sample rate */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
+                          hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
+
+       /* Set the number of channels we want to use */
+       if (params_channels(params) == 1)
+               val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
+       else
+               val = 0;
+
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
+                          val);
+
+       /* Set the number of sample bits to either 16 or 24 bits */
+       if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
+
+               /* Set TX FIFO mode to padding the LSBs with 0 */
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
+                                  0);
+
+               scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       } else {
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
+                                  0);
+
+               /* Set TX FIFO mode to repeat the MSB */
+               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
+
+               scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+       }
+
+       return 0;
+}
+
+static int sun4i_codec_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+       /*
+        * Stop issuing DRQ when we have room for less than 16 samples
+        * in our TX FIFO
+        */
+       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
+                          3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
+
+       return clk_prepare_enable(scodec->clk_module);
+}
+
+static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+       clk_disable_unprepare(scodec->clk_module);
+}
+
+static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
+       .startup        = sun4i_codec_startup,
+       .shutdown       = sun4i_codec_shutdown,
+       .trigger        = sun4i_codec_trigger,
+       .hw_params      = sun4i_codec_hw_params,
+       .prepare        = sun4i_codec_prepare,
+};
+
+static struct snd_soc_dai_driver sun4i_codec_dai = {
+       .name   = "Codec",
+       .ops    = &sun4i_codec_dai_ops,
+       .playback = {
+               .stream_name    = "Codec Playback",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rate_min       = 8000,
+               .rate_max       = 192000,
+               .rates          = SNDRV_PCM_RATE_8000_48000 |
+                                 SNDRV_PCM_RATE_96000 |
+                                 SNDRV_PCM_RATE_192000,
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+               .sig_bits       = 24,
+       },
+};
+
+/*** Codec ***/
+static const struct snd_kcontrol_new sun4i_codec_pa_mute =
+       SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
+
+static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
+
+static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
+       SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL,
+                      SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
+                      sun4i_codec_pa_volume_scale),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_right_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Right DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
+       SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
+                       SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
+       /* Digital parts of the DACs */
+       SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
+                           SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+                           NULL, 0),
+
+       /* Analog parts of the DACs */
+       SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
+                        SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
+                        SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
+
+       /* Mixers */
+       SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+                          sun4i_codec_left_mixer_controls,
+                          ARRAY_SIZE(sun4i_codec_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+                          sun4i_codec_right_mixer_controls,
+                          ARRAY_SIZE(sun4i_codec_right_mixer_controls)),
+
+       /* Global Mixer Enable */
+       SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
+                           SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
+
+       /* Pre-Amplifier */
+       SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+                          SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
+                          sun4i_codec_pa_mixer_controls,
+                          ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
+       SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0,
+                           &sun4i_codec_pa_mute),
+
+       SND_SOC_DAPM_OUTPUT("HP Right"),
+       SND_SOC_DAPM_OUTPUT("HP Left"),
+};
+
+static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
+       /* Left DAC Routes */
+       { "Left DAC", NULL, "DAC" },
+
+       /* Right DAC Routes */
+       { "Right DAC", NULL, "DAC" },
+
+       /* Right Mixer Routes */
+       { "Right Mixer", NULL, "Mixer Enable" },
+       { "Right Mixer", "Left DAC Playback Switch", "Left DAC" },
+       { "Right Mixer", "Right DAC Playback Switch", "Right DAC" },
+
+       /* Left Mixer Routes */
+       { "Left Mixer", NULL, "Mixer Enable" },
+       { "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
+
+       /* Pre-Amplifier Mixer Routes */
+       { "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" },
+       { "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" },
+       { "Pre-Amplifier", "DAC Playback Switch", "Left DAC" },
+       { "Pre-Amplifier", "DAC Playback Switch", "Right DAC" },
+
+       /* PA -> HP path */
+       { "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" },
+       { "HP Right", NULL, "Pre-Amplifier Mute" },
+       { "HP Left", NULL, "Pre-Amplifier Mute" },
+};
+
+static struct snd_soc_codec_driver sun4i_codec_codec = {
+       .controls               = sun4i_codec_widgets,
+       .num_controls           = ARRAY_SIZE(sun4i_codec_widgets),
+       .dapm_widgets           = sun4i_codec_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(sun4i_codec_dapm_widgets),
+       .dapm_routes            = sun4i_codec_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(sun4i_codec_dapm_routes),
+};
+
+static const struct snd_soc_component_driver sun4i_codec_component = {
+       .name = "sun4i-codec",
+};
+
+#define SUN4I_CODEC_RATES      SNDRV_PCM_RATE_8000_192000
+#define SUN4I_CODEC_FORMATS    (SNDRV_PCM_FMTBIT_S16_LE | \
+                                SNDRV_PCM_FMTBIT_S32_LE)
+
+static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
+{
+       struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+
+       snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
+                                 NULL);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver dummy_cpu_dai = {
+       .name   = "sun4i-codec-cpu-dai",
+       .probe  = sun4i_codec_dai_probe,
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SUN4I_CODEC_RATES,
+               .formats        = SUN4I_CODEC_FORMATS,
+               .sig_bits       = 24,
+       },
+};
+
+static const struct regmap_config sun4i_codec_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = SUN4I_CODEC_AC_MIC_PHONE_CAL,
+};
+
+static const struct of_device_id sun4i_codec_of_match[] = {
+       { .compatible = "allwinner,sun4i-a10-codec" },
+       { .compatible = "allwinner,sun7i-a20-codec" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
+
+static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
+                                                       int *num_links)
+{
+       struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
+                                                    GFP_KERNEL);
+       if (!link)
+               return NULL;
+
+       link->name              = "cdc";
+       link->stream_name       = "CDC PCM";
+       link->codec_dai_name    = "Codec";
+       link->cpu_dai_name      = dev_name(dev);
+       link->codec_name        = dev_name(dev);
+       link->platform_name     = dev_name(dev);
+       link->dai_fmt           = SND_SOC_DAIFMT_I2S;
+
+       *num_links = 1;
+
+       return link;
+};
+
+static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
+{
+       struct snd_soc_card *card;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return NULL;
+
+       card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+       if (!card->dai_link)
+               return NULL;
+
+       card->dev               = dev;
+       card->name              = "sun4i-codec";
+
+       return card;
+};
+
+static int sun4i_codec_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct sun4i_codec *scodec;
+       struct resource *res;
+       void __iomem *base;
+       int ret;
+
+       scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
+       if (!scodec)
+               return -ENOMEM;
+
+       scodec->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base)) {
+               dev_err(&pdev->dev, "Failed to map the registers\n");
+               return PTR_ERR(base);
+       }
+
+       scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                            &sun4i_codec_regmap_config);
+       if (IS_ERR(scodec->regmap)) {
+               dev_err(&pdev->dev, "Failed to create our regmap\n");
+               return PTR_ERR(scodec->regmap);
+       }
+
+       /* Get the clocks from the DT */
+       scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
+       if (IS_ERR(scodec->clk_apb)) {
+               dev_err(&pdev->dev, "Failed to get the APB clock\n");
+               return PTR_ERR(scodec->clk_apb);
+       }
+
+       scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
+       if (IS_ERR(scodec->clk_module)) {
+               dev_err(&pdev->dev, "Failed to get the module clock\n");
+               return PTR_ERR(scodec->clk_module);
+       }
+
+       /* Enable the bus clock */
+       if (clk_prepare_enable(scodec->clk_apb)) {
+               dev_err(&pdev->dev, "Failed to enable the APB clock\n");
+               return -EINVAL;
+       }
+
+       /* DMA configuration for TX FIFO */
+       scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
+       scodec->playback_dma_data.maxburst = 4;
+       scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
+                                    &sun4i_codec_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register our codec\n");
+               goto err_clk_disable;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &sun4i_codec_component,
+                                             &dummy_cpu_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register our DAI\n");
+               goto err_unregister_codec;
+       }
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
+               goto err_unregister_codec;
+       }
+
+       card = sun4i_codec_create_card(&pdev->dev);
+       if (!card) {
+               dev_err(&pdev->dev, "Failed to create our card\n");
+               goto err_unregister_codec;
+       }
+
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, scodec);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register our card\n");
+               goto err_unregister_codec;
+       }
+
+       return 0;
+
+err_unregister_codec:
+       snd_soc_unregister_codec(&pdev->dev);
+err_clk_disable:
+       clk_disable_unprepare(scodec->clk_apb);
+       return ret;
+}
+
+static int sun4i_codec_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+       snd_soc_unregister_codec(&pdev->dev);
+       clk_disable_unprepare(scodec->clk_apb);
+
+       return 0;
+}
+
+static struct platform_driver sun4i_codec_driver = {
+       .driver = {
+               .name = "sun4i-codec",
+               .of_match_table = sun4i_codec_of_match,
+       },
+       .probe = sun4i_codec_probe,
+       .remove = sun4i_codec_remove,
+};
+module_platform_driver(sun4i_codec_driver);
+
+MODULE_DESCRIPTION("Allwinner A10 codec driver");
+MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_LICENSE("GPL");
index 4e0c0e502ade2c228a00db3a44c44ecfa4c9978d..ba9fc099cf67b22997aad328f256c2b1150c86a1 100644 (file)
@@ -152,6 +152,7 @@ static const struct of_device_id snd_soc_mop500_match[] = {
        { .compatible = "stericsson,snd-soc-mop500", },
        {},
 };
+MODULE_DEVICE_TABLE(of, snd_soc_mop500_match);
 
 static struct platform_driver snd_soc_mop500_driver = {
        .driver = {
index f5df08ded770ef9cbafd3ec88903893bc4657344..6d5698b25bd4b25c92c128860527245167d665d0 100644 (file)
@@ -522,9 +522,9 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
                slots_active = hweight32(mask);
                dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
 
-               snd_pcm_hw_constraint_minmax(runtime,
+               snd_pcm_hw_constraint_single(runtime,
                                SNDRV_PCM_HW_PARAM_CHANNELS,
-                               slots_active, slots_active);
+                               slots_active);
                break;
 
        default:
@@ -843,6 +843,7 @@ static const struct of_device_id ux500_msp_i2s_match[] = {
        { .compatible = "stericsson,ux500-msp-i2s", },
        {},
 };
+MODULE_DEVICE_TABLE(of, ux500_msp_i2s_match);
 
 static struct platform_driver msp_i2s_driver = {
        .driver = {
index ef580b43f1e3b1e71dcc4ed0f6a16f11928e071e..71778ca4b26aafcb3dacedcc660947a5df61f7e2 100644 (file)
@@ -122,6 +122,7 @@ struct snd_usb_substream {
        unsigned int buffer_periods;    /* current periods per buffer */
        unsigned int altset_idx;     /* USB data format: index of alternate setting */
        unsigned int txfr_quirk:1;      /* allow sub-frame alignment */
+       unsigned int tx_length_quirk:1; /* add length specifier to transfers */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
        unsigned int pkt_offset_adj;    /* Bytes to drop from beginning of packets (for non-compliant devices) */
 
index e6f71894ecdc950117776d2ef9e2cc4df4661904..7b1cb365ffab74d6028206adb8012226da963bac 100644 (file)
@@ -183,13 +183,53 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
                ep->retire_data_urb(ep->data_subs, urb);
 }
 
+static void prepare_silent_urb(struct snd_usb_endpoint *ep,
+                              struct snd_urb_ctx *ctx)
+{
+       struct urb *urb = ctx->urb;
+       unsigned int offs = 0;
+       unsigned int extra = 0;
+       __le32 packet_length;
+       int i;
+
+       /* For tx_length_quirk, put packet length at start of packet */
+       if (ep->chip->tx_length_quirk)
+               extra = sizeof(packet_length);
+
+       for (i = 0; i < ctx->packets; ++i) {
+               unsigned int offset;
+               unsigned int length;
+               int counts;
+
+               if (ctx->packet_size[i])
+                       counts = ctx->packet_size[i];
+               else
+                       counts = snd_usb_endpoint_next_packet_size(ep);
+
+               length = counts * ep->stride; /* number of silent bytes */
+               offset = offs * ep->stride + extra * i;
+               urb->iso_frame_desc[i].offset = offset;
+               urb->iso_frame_desc[i].length = length + extra;
+               if (extra) {
+                       packet_length = cpu_to_le32(length);
+                       memcpy(urb->transfer_buffer + offset,
+                              &packet_length, sizeof(packet_length));
+               }
+               memset(urb->transfer_buffer + offset + extra,
+                      ep->silence_value, length);
+               offs += counts;
+       }
+
+       urb->number_of_packets = ctx->packets;
+       urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra;
+}
+
 /*
  * Prepare a PLAYBACK urb for submission to the bus.
  */
 static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
                                 struct snd_urb_ctx *ctx)
 {
-       int i;
        struct urb *urb = ctx->urb;
        unsigned char *cp = urb->transfer_buffer;
 
@@ -201,24 +241,7 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
                        ep->prepare_data_urb(ep->data_subs, urb);
                } else {
                        /* no data provider, so send silence */
-                       unsigned int offs = 0;
-                       for (i = 0; i < ctx->packets; ++i) {
-                               int counts;
-
-                               if (ctx->packet_size[i])
-                                       counts = ctx->packet_size[i];
-                               else
-                                       counts = snd_usb_endpoint_next_packet_size(ep);
-
-                               urb->iso_frame_desc[i].offset = offs * ep->stride;
-                               urb->iso_frame_desc[i].length = counts * ep->stride;
-                               offs += counts;
-                       }
-
-                       urb->number_of_packets = ctx->packets;
-                       urb->transfer_buffer_length = offs * ep->stride;
-                       memset(urb->transfer_buffer, ep->silence_value,
-                              offs * ep->stride);
+                       prepare_silent_urb(ep, ctx);
                }
                break;
 
@@ -594,6 +617,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        unsigned int max_packs_per_period, urbs_per_period, urb_packs;
        unsigned int max_urbs, i;
        int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
+       int tx_length_quirk = (ep->chip->tx_length_quirk &&
+                              usb_pipeout(ep->pipe));
 
        if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
                /*
@@ -610,13 +635,34 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 
        /* assume max. frequency is 25% higher than nominal */
        ep->freqmax = ep->freqn + (ep->freqn >> 2);
-       maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
-                               >> (16 - ep->datainterval);
+       /* Round up freqmax to nearest integer in order to calculate maximum
+        * packet size, which must represent a whole number of frames.
+        * This is accomplished by adding 0x0.ffff before converting the
+        * Q16.16 format into integer.
+        * In order to accurately calculate the maximum packet size when
+        * the data interval is more than 1 (i.e. ep->datainterval > 0),
+        * multiply by the data interval prior to rounding. For instance,
+        * a freqmax of 41 kHz will result in a max packet size of 6 (5.125)
+        * frames with a data interval of 1, but 11 (10.25) frames with a
+        * data interval of 2.
+        * (ep->freqmax << ep->datainterval overflows at 8.192 MHz for the
+        * maximum datainterval value of 3, at USB full speed, higher for
+        * USB high speed, noting that ep->freqmax is in units of
+        * frames per packet in Q16.16 format.)
+        */
+       maxsize = (((ep->freqmax << ep->datainterval) + 0xffff) >> 16) *
+                        (frame_bits >> 3);
+       if (tx_length_quirk)
+               maxsize += sizeof(__le32); /* Space for length descriptor */
        /* but wMaxPacketSize might reduce this */
        if (ep->maxpacksize && ep->maxpacksize < maxsize) {
                /* whatever fits into a max. size packet */
-               maxsize = ep->maxpacksize;
-               ep->freqmax = (maxsize / (frame_bits >> 3))
+               unsigned int data_maxsize = maxsize = ep->maxpacksize;
+
+               if (tx_length_quirk)
+                       /* Need to remove the length descriptor to calc freq */
+                       data_maxsize -= sizeof(__le32);
+               ep->freqmax = (data_maxsize / (frame_bits >> 3))
                                << (16 - ep->datainterval);
        }
 
index 417ebb11cf4896b8009c0aa86c7dab71c34d61a4..7661616f36361d142144842bd6595994829edec4 100644 (file)
@@ -1903,11 +1903,14 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi *umidi)
 
        hostif = &intf->altsetting[1];
        intfd = get_iface_desc(hostif);
+       /* If either or both of the endpoints support interrupt transfer,
+        * then use the alternate setting
+        */
        if (intfd->bNumEndpoints != 2 ||
-           (get_endpoint(hostif, 0)->bmAttributes &
-            USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
-           (get_endpoint(hostif, 1)->bmAttributes &
-            USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
+           !((get_endpoint(hostif, 0)->bmAttributes &
+              USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT ||
+             (get_endpoint(hostif, 1)->bmAttributes &
+              USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
                return;
 
        dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n",
index d3608c0a29f343f32179b33b74f537172484fb4b..fe91184ce83247d8b0360bab09e94c8f7cb720d8 100644 (file)
@@ -338,7 +338,7 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
        struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
        struct usb_mixer_interface *mixer = list->mixer;
        int index = kcontrol->private_value & 0xff;
-       int value = ucontrol->value.integer.value[0];
+       unsigned int value = ucontrol->value.integer.value[0];
        int old_value = kcontrol->private_value >> 8;
        int err;
 
index cdac5179db3f349f8ac61e010a8a9ff05c2e93ae..9245f52d43bdecfeb710b6cfc6ae99b3202aae90 100644 (file)
@@ -1383,6 +1383,56 @@ static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs,
                        subs->hwptr_done++;
                }
        }
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               subs->hwptr_done -= runtime->buffer_size * stride;
+}
+
+static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb,
+                       int offset, int stride, unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+
+       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int bytes1 =
+                       runtime->buffer_size * stride - subs->hwptr_done;
+               memcpy(urb->transfer_buffer + offset,
+                      runtime->dma_area + subs->hwptr_done, bytes1);
+               memcpy(urb->transfer_buffer + offset + bytes1,
+                      runtime->dma_area, bytes - bytes1);
+       } else {
+               memcpy(urb->transfer_buffer + offset,
+                      runtime->dma_area + subs->hwptr_done, bytes);
+       }
+       subs->hwptr_done += bytes;
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               subs->hwptr_done -= runtime->buffer_size * stride;
+}
+
+static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs,
+                                     struct urb *urb, int stride,
+                                     unsigned int bytes)
+{
+       __le32 packet_length;
+       int i;
+
+       /* Put __le32 length descriptor at start of each packet. */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int length = urb->iso_frame_desc[i].length;
+               unsigned int offset = urb->iso_frame_desc[i].offset;
+
+               packet_length = cpu_to_le32(length);
+               offset += i * sizeof(packet_length);
+               urb->iso_frame_desc[i].offset = offset;
+               urb->iso_frame_desc[i].length += sizeof(packet_length);
+               memcpy(urb->transfer_buffer + offset,
+                      &packet_length, sizeof(packet_length));
+               copy_to_urb(subs, urb, offset + sizeof(packet_length),
+                           stride, length);
+       }
+       /* Adjust transfer size accordingly. */
+       bytes += urb->number_of_packets * sizeof(packet_length);
+       return bytes;
 }
 
 static void prepare_playback_urb(struct snd_usb_substream *subs,
@@ -1460,27 +1510,17 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
                }
 
                subs->hwptr_done += bytes;
+               if (subs->hwptr_done >= runtime->buffer_size * stride)
+                       subs->hwptr_done -= runtime->buffer_size * stride;
        } else {
                /* usual PCM */
-               if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-                       /* err, the transferred area goes over buffer boundary. */
-                       unsigned int bytes1 =
-                               runtime->buffer_size * stride - subs->hwptr_done;
-                       memcpy(urb->transfer_buffer,
-                              runtime->dma_area + subs->hwptr_done, bytes1);
-                       memcpy(urb->transfer_buffer + bytes1,
-                              runtime->dma_area, bytes - bytes1);
-               } else {
-                       memcpy(urb->transfer_buffer,
-                              runtime->dma_area + subs->hwptr_done, bytes);
-               }
-
-               subs->hwptr_done += bytes;
+               if (!subs->tx_length_quirk)
+                       copy_to_urb(subs, urb, 0, stride, bytes);
+               else
+                       bytes = copy_to_urb_quirk(subs, urb, stride, bytes);
+                       /* bytes is now amount of outgoing data */
        }
 
-       if (subs->hwptr_done >= runtime->buffer_size * stride)
-               subs->hwptr_done -= runtime->buffer_size * stride;
-
        /* update delay with exact number of samples queued */
        runtime->delay = subs->last_delay;
        runtime->delay += frames;
index e4756651a52c8873457ae340450934dcfbd5dfad..1a1e2e4df35e5809e7f7d81b405ca6dddf2f4311 100644 (file)
@@ -2663,6 +2663,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_NOVATION
        }
 },
+{
+       USB_DEVICE(0x1235, 0x000a),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Novation", */
+               /* .product_name = "Nocturn", */
+               .ifnum = 0,
+               .type = QUIRK_MIDI_RAW_BYTES
+       }
+},
 {
        USB_DEVICE(0x1235, 0x000e),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -3182,25 +3191,19 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
 {
        /*
         * ZOOM R16/24 in audio interface mode.
-        * Mixer descriptors are garbage, further quirks will be needed
-        * to make any of it functional, thus disabled for now.
-        * Playback stream appears to start and run fine but no sound
-        * is produced, so also disabled for now.
+        * Playback requires an extra four byte LE length indicator
+        * at the start of each isochronous packet. This quirk is
+        * enabled in create_standard_audio_quirk().
         */
        USB_DEVICE(0x1686, 0x00dd),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               /* Mixer */
-                               .ifnum = 0,
-                               .type = QUIRK_IGNORE_INTERFACE,
-                       },
                        {
                                /* Playback  */
                                .ifnum = 1,
-                               .type = QUIRK_IGNORE_INTERFACE,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE,
                        },
                        {
                                /* Capture */
index 00ebc0ca008e08b98b2f5fb6aed67dfb0d642ec1..4897ea171194f474c352c45579f62aa036d219ea 100644 (file)
@@ -115,6 +115,9 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
        struct usb_interface_descriptor *altsd;
        int err;
 
+       if (chip->usb_id == USB_ID(0x1686, 0x00dd)) /* Zoom R16/24 */
+               chip->tx_length_quirk = 1;
+
        alts = &iface->altsetting[0];
        altsd = get_iface_desc(alts);
        err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
index 970086015cded9f0a75f4d66a1471b1e99d9bfd4..8ee14f2365e749d964c369acef5ac45f95a060ca 100644 (file)
@@ -92,6 +92,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
        subs->direction = stream;
        subs->dev = as->chip->dev;
        subs->txfr_quirk = as->chip->txfr_quirk;
+       subs->tx_length_quirk = as->chip->tx_length_quirk;
        subs->speed = snd_usb_get_speed(subs->dev);
        subs->pkt_offset_adj = 0;
 
index 33a176437e2e4fc34f5064fc23984bab60b22795..15a12715bd05154bd9c0b4bbe7084f3df15022b2 100644 (file)
@@ -43,6 +43,7 @@ struct snd_usb_audio {
        atomic_t usage_count;
        wait_queue_head_t shutdown_wait;
        unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
+       unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
        
        int num_interfaces;
        int num_suspended_intf;